mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-07 23:00:23 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab5e80a8ef | ||
|
|
ffb301b38c | ||
|
|
9744585cf0 | ||
|
|
7cf363e315 | ||
|
|
9c4a906ec0 | ||
|
|
d6030195f9 | ||
|
|
c607fa30c4 | ||
|
|
eebf2877f3 | ||
|
|
7f60358eac | ||
|
|
85c6b3cea4 | ||
|
|
dda68d48b4 | ||
|
|
5c36f6e909 | ||
|
|
f112ca6768 | ||
|
|
a93dac0e28 | ||
|
|
35690d8521 | ||
|
|
1bed4afb97 |
No files matched your search
@@ -5,5 +5,6 @@ ipch
|
||||
*.aps
|
||||
*.user
|
||||
/OpenVR-SpaceCalibrator/x64/
|
||||
/OpenVR-SpaceCalibratorDriver/x64/
|
||||
/x64/
|
||||
/lib/boost*
|
||||
@@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenVR-SpaceCalibrator", "OpenVR-SpaceCalibrator\OpenVR-SpaceCalibrator.vcxproj", "{63BAE169-D595-4464-8E7E-50D6FD379348}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenVR-SpaceCalibratorDriver", "OpenVR-SpaceCalibratorDriver\OpenVR-SpaceCalibratorDriver.vcxproj", "{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -15,6 +17,10 @@ Global
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Debug|x64.Build.0 = Debug|x64
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Release|x64.ActiveCfg = Release|x64
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Release|x64.Build.0 = Release|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Debug|x64.Build.0 = Debug|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Release|x64.ActiveCfg = Release|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
#include "stdafx.h"
|
||||
#include "Calibration.h"
|
||||
#include "Configuration.h"
|
||||
#include "IPCClient.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <lib_vrinputemulator/vrinputemulator.h>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
|
||||
static vrinputemulator::VRInputEmulator InputEmulator;
|
||||
static IPCClient Driver;
|
||||
CalibrationContext CalCtx;
|
||||
|
||||
void InitVR()
|
||||
void InitCalibrator()
|
||||
{
|
||||
auto initError = vr::VRInitError_None;
|
||||
vr::VR_Init(&initError, vr::VRApplication_Other);
|
||||
if (initError != vr::VRInitError_None)
|
||||
{
|
||||
auto error = vr::VR_GetVRInitErrorAsEnglishDescription(initError);
|
||||
throw std::runtime_error("OpenVR error:" + std::string(error));
|
||||
}
|
||||
|
||||
if (!vr::VR_IsInterfaceVersionValid(vr::IVRSystem_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSystem_Version");
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVRSettings_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSettings_Version");
|
||||
}
|
||||
|
||||
InputEmulator.connect();
|
||||
Driver.Connect();
|
||||
}
|
||||
|
||||
struct Pose
|
||||
@@ -277,9 +260,25 @@ vr::HmdVector3d_t VRTranslationVec(Eigen::Vector3d transcm)
|
||||
return vrTrans;
|
||||
}
|
||||
|
||||
void ResetAndDisableOffsets(uint32_t id)
|
||||
{
|
||||
vr::HmdVector3d_t zeroV;
|
||||
zeroV.v[0] = zeroV.v[1] = zeroV.v[2] = 0;
|
||||
|
||||
vr::HmdQuaternion_t zeroQ;
|
||||
zeroQ.x = 0; zeroQ.y = 0; zeroQ.z = 0; zeroQ.w = 1;
|
||||
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = { id, false, zeroV, zeroQ };
|
||||
Driver.SendBlocking(req);
|
||||
}
|
||||
|
||||
static_assert(vr::k_unTrackedDeviceIndex_Hmd == 0, "HMD index expected to be 0");
|
||||
|
||||
void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
{
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
ctx.enabled = ctx.validProfile;
|
||||
|
||||
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
|
||||
{
|
||||
@@ -292,53 +291,72 @@ void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
auto universeId = vr::VRSystem()->GetUint64TrackedDeviceProperty(id, vr::Prop_CurrentUniverseId_Uint64, &err);
|
||||
printf("uid %d err %d\n", universeId, err);
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if (!ctx.enabled)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_TrackingSystemName_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
|
||||
if (err != vr::TrackedProp_Success)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string trackingSystem(buffer);
|
||||
|
||||
if (trackingSystem != ctx.targetTrackingSystem)
|
||||
continue;
|
||||
|
||||
if (deviceClass == vr::TrackedDeviceClass_TrackingReference || deviceClass == vr::TrackedDeviceClass_HMD)
|
||||
if (id == vr::k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
// TODO(pushrax): detect zero reference switches and adjust calibration automatically
|
||||
//auto p = ctx.devicePoses[id].mDeviceToAbsoluteTracking.m;
|
||||
//printf("REF %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
//printf("HMD %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
|
||||
if (trackingSystem != ctx.referenceTrackingSystem)
|
||||
{
|
||||
// Currently using an HMD with a different tracking system than the calibration.
|
||||
ctx.enabled = false;
|
||||
}
|
||||
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
if (trackingSystem != ctx.targetTrackingSystem)
|
||||
{
|
||||
//printf("setting calibration for %d (%s)\n", id, buffer);
|
||||
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
|
||||
InputEmulator.setWorldFromDriverRotationOffset(id, vrRotQuat);
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto vrTransVec = VRTranslationVec(ctx.calibratedTranslation);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(id, vrTransVec);
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = {
|
||||
id,
|
||||
true,
|
||||
VRTranslationVec(ctx.calibratedTranslation),
|
||||
VRRotationQuat(ctx.calibratedRotation)
|
||||
};
|
||||
Driver.SendBlocking(req);
|
||||
}
|
||||
|
||||
InputEmulator.enableDeviceOffsets(id, true);
|
||||
if (ctx.enabled && ctx.chaperone.valid && ctx.chaperone.autoApply)
|
||||
{
|
||||
uint32_t quadCount = 0;
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(nullptr, &quadCount);
|
||||
|
||||
// Heuristic: when SteamVR resets to a blank-ish chaperone, it uses empty geometry,
|
||||
// but manual adjustments (e.g. via a play space mover) will not touch geometry.
|
||||
if (quadCount != ctx.chaperone.geometry.size())
|
||||
{
|
||||
ApplyChaperoneBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAndDisableOffsets(uint32_t id)
|
||||
{
|
||||
vr::HmdVector3d_t zeroV;
|
||||
zeroV.v[0] = zeroV.v[1] = zeroV.v[2] = 0;
|
||||
|
||||
vr::HmdQuaternion_t zeroQ;
|
||||
zeroQ.x = 0; zeroQ.y = 0; zeroQ.z = 0; zeroQ.w = 1;
|
||||
|
||||
InputEmulator.setWorldFromDriverRotationOffset(id, zeroQ);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(id, zeroV);
|
||||
InputEmulator.enableDeviceOffsets(id, false);
|
||||
}
|
||||
|
||||
void StartCalibration()
|
||||
{
|
||||
CalCtx.state = CalibrationState::Begin;
|
||||
@@ -362,10 +380,7 @@ void CalibrationTick(double time)
|
||||
{
|
||||
ctx.wantedUpdateInterval = 1.0;
|
||||
|
||||
if (!ctx.validProfile)
|
||||
return;
|
||||
|
||||
if ((time - ctx.timeLastScan) >= 2.5)
|
||||
if ((time - ctx.timeLastScan) >= 1.0)
|
||||
{
|
||||
ScanAndApplyProfile(ctx);
|
||||
ctx.timeLastScan = time;
|
||||
@@ -375,12 +390,13 @@ void CalibrationTick(double time)
|
||||
|
||||
if (ctx.state == CalibrationState::Editing)
|
||||
{
|
||||
ctx.wantedUpdateInterval = 0.0;
|
||||
ctx.wantedUpdateInterval = 0.1;
|
||||
|
||||
if (!ctx.validProfile)
|
||||
return;
|
||||
|
||||
ScanAndApplyProfile(ctx);
|
||||
if ((time - ctx.timeLastScan) >= 0.1)
|
||||
{
|
||||
ScanAndApplyProfile(ctx);
|
||||
ctx.timeLastScan = time;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -442,8 +458,10 @@ void CalibrationTick(double time)
|
||||
ctx.calibratedRotation = CalibrateRotation(samples);
|
||||
|
||||
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
|
||||
InputEmulator.setWorldFromDriverRotationOffset(ctx.targetID, vrRotQuat);
|
||||
InputEmulator.enableDeviceOffsets(ctx.targetID, true);
|
||||
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = { ctx.targetID, true, vrRotQuat };
|
||||
Driver.SendBlocking(req);
|
||||
|
||||
ctx.state = CalibrationState::Translation;
|
||||
}
|
||||
@@ -452,8 +470,12 @@ void CalibrationTick(double time)
|
||||
ctx.calibratedTranslation = CalibrateTranslation(samples);
|
||||
|
||||
auto vrTrans = VRTranslationVec(ctx.calibratedTranslation);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(ctx.targetID, vrTrans);
|
||||
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = { ctx.targetID, true, vrTrans };
|
||||
Driver.SendBlocking(req);
|
||||
|
||||
ctx.validProfile = true;
|
||||
SaveProfile(ctx);
|
||||
CalCtx.Message("Finished calibration, profile saved\n");
|
||||
|
||||
@@ -463,3 +485,26 @@ void CalibrationTick(double time)
|
||||
samples.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void LoadChaperoneBounds()
|
||||
{
|
||||
vr::VRChaperoneSetup()->RevertWorkingCopy();
|
||||
|
||||
uint32_t quadCount = 0;
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(nullptr, &quadCount);
|
||||
|
||||
CalCtx.chaperone.geometry.resize(quadCount);
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(&CalCtx.chaperone.geometry[0], &quadCount);
|
||||
vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(&CalCtx.chaperone.standingCenter);
|
||||
vr::VRChaperoneSetup()->GetWorkingPlayAreaSize(&CalCtx.chaperone.playSpaceSize.v[0], &CalCtx.chaperone.playSpaceSize.v[1]);
|
||||
CalCtx.chaperone.valid = true;
|
||||
}
|
||||
|
||||
void ApplyChaperoneBounds()
|
||||
{
|
||||
vr::VRChaperoneSetup()->RevertWorkingCopy();
|
||||
vr::VRChaperoneSetup()->SetWorkingCollisionBoundsInfo(&CalCtx.chaperone.geometry[0], CalCtx.chaperone.geometry.size());
|
||||
vr::VRChaperoneSetup()->SetWorkingStandingZeroPoseToRawTrackingPose(&CalCtx.chaperone.standingCenter);
|
||||
vr::VRChaperoneSetup()->SetWorkingPlayAreaSize(CalCtx.chaperone.playSpaceSize.v[0], CalCtx.chaperone.playSpaceSize.v[1]);
|
||||
vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <openvr.h>
|
||||
#include <vector>
|
||||
|
||||
enum class CalibrationState
|
||||
{
|
||||
@@ -15,7 +16,7 @@ enum class CalibrationState
|
||||
struct CalibrationContext
|
||||
{
|
||||
CalibrationState state = CalibrationState::None;
|
||||
int referenceID, targetID;
|
||||
uint32_t referenceID, targetID;
|
||||
|
||||
Eigen::Vector3d calibratedRotation;
|
||||
Eigen::Vector3d calibratedTranslation;
|
||||
@@ -23,12 +24,22 @@ struct CalibrationContext
|
||||
std::string referenceTrackingSystem;
|
||||
std::string targetTrackingSystem;
|
||||
|
||||
bool enabled = false;
|
||||
bool validProfile = false;
|
||||
double timeLastTick = 0, timeLastScan = 0;
|
||||
double wantedUpdateInterval = 1.0;
|
||||
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
|
||||
|
||||
struct Chaperone
|
||||
{
|
||||
bool valid = false;
|
||||
bool autoApply = true;
|
||||
std::vector<vr::HmdQuad_t> geometry;
|
||||
vr::HmdMatrix34_t standingCenter;
|
||||
vr::HmdVector2_t playSpaceSize;
|
||||
} chaperone;
|
||||
|
||||
std::string messages;
|
||||
|
||||
void Message(const std::string &msg)
|
||||
@@ -36,10 +47,27 @@ struct CalibrationContext
|
||||
messages += msg;
|
||||
std::cerr << msg;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
chaperone.geometry.clear();
|
||||
chaperone.standingCenter = vr::HmdMatrix34_t();
|
||||
chaperone.playSpaceSize = vr::HmdVector2_t();
|
||||
chaperone.valid = false;
|
||||
|
||||
calibratedRotation = Eigen::Vector3d();
|
||||
calibratedTranslation = Eigen::Vector3d();
|
||||
referenceTrackingSystem = "";
|
||||
targetTrackingSystem = "";
|
||||
enabled = false;
|
||||
validProfile = false;
|
||||
}
|
||||
};
|
||||
|
||||
extern CalibrationContext CalCtx;
|
||||
|
||||
void InitVR();
|
||||
void InitCalibrator();
|
||||
void CalibrationTick(double time);
|
||||
void StartCalibration();
|
||||
void StartCalibration();
|
||||
void LoadChaperoneBounds();
|
||||
void ApplyChaperoneBounds();
|
||||
@@ -12,13 +12,54 @@
|
||||
static void UpgradeProfileV1(CalibrationContext &ctx);
|
||||
static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream);
|
||||
|
||||
static std::string ConfigFileName()
|
||||
{
|
||||
char cruntimePath[MAX_PATH] = { 0 };
|
||||
unsigned int pathLen;
|
||||
vr::VR_GetRuntimePath(cruntimePath, MAX_PATH, &pathLen);
|
||||
std::string vrRuntimeConfigName(cruntimePath);
|
||||
return vrRuntimeConfigName + "\\..\\..\\..\\config\\01spacecalibrator\\calibration.json";
|
||||
}
|
||||
|
||||
picojson::array FloatArray(const float *buf, int numFloats)
|
||||
{
|
||||
picojson::array arr;
|
||||
|
||||
for (int i = 0; i < numFloats; i++)
|
||||
arr.push_back(picojson::value(double(buf[i])));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
void LoadFloatArray(const picojson::value &obj, float *buf, int numFloats)
|
||||
{
|
||||
if (!obj.is<picojson::array>())
|
||||
throw std::runtime_error("expected array, got " + obj.to_str());
|
||||
|
||||
auto &arr = obj.get<picojson::array>();
|
||||
if (arr.size() != numFloats)
|
||||
throw std::runtime_error("wrong buffer size");
|
||||
|
||||
for (int i = 0; i < numFloats; i++)
|
||||
buf[i] = (float) arr[i].get<double>();
|
||||
}
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::ifstream file("openvr_space_calibration.json");
|
||||
ctx.validProfile = false;
|
||||
|
||||
std::ifstream file(ConfigFileName());
|
||||
if (!file.good())
|
||||
{
|
||||
std::cout << "Profile missing, trying fallback path" << std::endl;
|
||||
// Fallback to working directory, which was the default for a long time.
|
||||
file = std::ifstream("openvr_space_calibration.json");
|
||||
}
|
||||
|
||||
|
||||
if (!file.good())
|
||||
{
|
||||
std::cout << "Fallback profile missing, trying V1 path" << std::endl;
|
||||
UpgradeProfileV1(ctx);
|
||||
return;
|
||||
}
|
||||
@@ -56,12 +97,47 @@ static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream)
|
||||
ctx.calibratedTranslation(1) = obj["y"].get<double>();
|
||||
ctx.calibratedTranslation(2) = obj["z"].get<double>();
|
||||
|
||||
if (obj["chaperone"].is<picojson::object>())
|
||||
{
|
||||
auto chaperone = obj["chaperone"].get<picojson::object>();
|
||||
ctx.chaperone.autoApply = chaperone["auto_apply"].get<bool>();
|
||||
|
||||
LoadFloatArray(chaperone["play_space_size"], ctx.chaperone.playSpaceSize.v, 2);
|
||||
|
||||
LoadFloatArray(
|
||||
chaperone["standing_center"],
|
||||
(float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter.m) / sizeof(float)
|
||||
);
|
||||
|
||||
if (!chaperone["geometry"].is<picojson::array>())
|
||||
throw std::runtime_error("chaperone geometry is not an array");
|
||||
|
||||
auto &geometry = chaperone["geometry"].get<picojson::array>();
|
||||
|
||||
if (geometry.size() > 0)
|
||||
{
|
||||
ctx.chaperone.geometry.resize(geometry.size() * sizeof(float) / sizeof(ctx.chaperone.geometry[0]));
|
||||
LoadFloatArray(chaperone["geometry"], (float *) ctx.chaperone.geometry.data(), geometry.size());
|
||||
|
||||
ctx.chaperone.valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
void SaveProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::ofstream file("openvr_space_calibration.json");
|
||||
std::cout << "Saving profile to " << ConfigFileName() << std::endl;
|
||||
|
||||
std::ofstream file(ConfigFileName());
|
||||
|
||||
if (!ctx.validProfile)
|
||||
{
|
||||
file << "[]";
|
||||
return;
|
||||
}
|
||||
|
||||
picojson::object profile;
|
||||
profile["reference_tracking_system"].set<std::string>(ctx.referenceTrackingSystem);
|
||||
@@ -73,6 +149,25 @@ void SaveProfile(CalibrationContext &ctx)
|
||||
profile["y"].set<double>(ctx.calibratedTranslation(1));
|
||||
profile["z"].set<double>(ctx.calibratedTranslation(2));
|
||||
|
||||
if (ctx.chaperone.valid)
|
||||
{
|
||||
picojson::object chaperone;
|
||||
chaperone["auto_apply"].set<bool>(ctx.chaperone.autoApply);
|
||||
chaperone["play_space_size"].set<picojson::array>(FloatArray(ctx.chaperone.playSpaceSize.v, 2));
|
||||
|
||||
chaperone["standing_center"].set<picojson::array>(FloatArray(
|
||||
(float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter.m) / sizeof(float)
|
||||
));
|
||||
|
||||
chaperone["geometry"].set<picojson::array>(FloatArray(
|
||||
(float *) ctx.chaperone.geometry.data(),
|
||||
sizeof(ctx.chaperone.geometry[0]) / sizeof(float) * ctx.chaperone.geometry.size()
|
||||
));
|
||||
|
||||
profile["chaperone"].set<picojson::object>(chaperone);
|
||||
}
|
||||
|
||||
picojson::value profileV;
|
||||
profileV.set<picojson::object>(profile);
|
||||
|
||||
@@ -83,8 +178,6 @@ void SaveProfile(CalibrationContext &ctx)
|
||||
profilesV.set<picojson::array>(profiles);
|
||||
|
||||
file << profilesV.serialize(true);
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
static void UpgradeProfileV1(CalibrationContext &ctx)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "stdafx.h"
|
||||
#include "IPCClient.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
static std::string LastErrorString(DWORD lastError)
|
||||
{
|
||||
LPSTR buffer = nullptr;
|
||||
size_t size = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buffer, 0, NULL
|
||||
);
|
||||
|
||||
std::string message(buffer, size);
|
||||
LocalFree(buffer);
|
||||
return message;
|
||||
}
|
||||
|
||||
IPCClient::~IPCClient()
|
||||
{
|
||||
if (pipe && pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pipe);
|
||||
}
|
||||
|
||||
void IPCClient::Connect()
|
||||
{
|
||||
LPTSTR pipeName = TEXT(OPENVR_SPACECALIBRATOR_PIPE_NAME);
|
||||
|
||||
WaitNamedPipe(pipeName, 1000);
|
||||
pipe = CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
|
||||
if (pipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw std::runtime_error("Space Calibrator driver unavailable, is SteamVR running and not in safe mode? Error: " + LastErrorString(GetLastError()));
|
||||
}
|
||||
|
||||
DWORD mode = PIPE_READMODE_MESSAGE;
|
||||
if (!SetNamedPipeHandleState(pipe, &mode, 0, 0))
|
||||
{
|
||||
throw std::runtime_error("Couldn't set pipe mode. Error: " + LastErrorString(GetLastError()));
|
||||
}
|
||||
|
||||
auto response = SendBlocking(protocol::Request(protocol::RequestHandshake));
|
||||
if (response.type != protocol::ResponseHandshake || response.protocol.version != protocol::Version)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Incorrect driver version installed, try reinstalling OpenVR-SpaceCalibrator. (Client: " +
|
||||
std::to_string(protocol::Version) +
|
||||
", Driver: " +
|
||||
std::to_string(response.protocol.version) +
|
||||
")"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protocol::Response IPCClient::SendBlocking(const protocol::Request &request)
|
||||
{
|
||||
Send(request);
|
||||
return Receive();
|
||||
}
|
||||
|
||||
void IPCClient::Send(const protocol::Request &request)
|
||||
{
|
||||
DWORD bytesWritten;
|
||||
BOOL success = WriteFile(pipe, &request, sizeof request, &bytesWritten, 0);
|
||||
if (!success)
|
||||
{
|
||||
throw std::runtime_error("Error writing IPC request. Error: " + LastErrorString(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
protocol::Response IPCClient::Receive()
|
||||
{
|
||||
protocol::Response response(protocol::ResponseInvalid);
|
||||
DWORD bytesRead;
|
||||
|
||||
BOOL success = ReadFile(pipe, &response, sizeof response, &bytesRead, 0);
|
||||
if (!success)
|
||||
{
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_MORE_DATA)
|
||||
{
|
||||
throw std::runtime_error("Error reading IPC response. Error: " + LastErrorString(lastError));
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesRead != sizeof response)
|
||||
{
|
||||
throw std::runtime_error("Invalid IPC response with size " + std::to_string(bytesRead));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Protocol.h"
|
||||
|
||||
class IPCClient
|
||||
{
|
||||
public:
|
||||
~IPCClient();
|
||||
|
||||
void Connect();
|
||||
protocol::Response SendBlocking(const protocol::Request &request);
|
||||
|
||||
void Send(const protocol::Request &request);
|
||||
protocol::Response Receive();
|
||||
|
||||
private:
|
||||
HANDLE pipe = INVALID_HANDLE_VALUE;
|
||||
};
|
||||
@@ -9,11 +9,15 @@
|
||||
#include <imgui/imgui_impl_opengl3.h>
|
||||
#include <GL/gl3w.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <openvr.h>
|
||||
#include <direct.h>
|
||||
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' \
|
||||
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
|
||||
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
#define OPENVR_APPLICATION_KEY "pushrax.SpaceCalibrator"
|
||||
|
||||
void CreateConsole()
|
||||
{
|
||||
static bool created = false;
|
||||
@@ -33,15 +37,27 @@ void GLFWErrorCallback(int error, const char* description)
|
||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
GLFWwindow *glfwWindow = nullptr;
|
||||
|
||||
static void HandleCommandLine(LPWSTR lpCmdLine);
|
||||
|
||||
static GLFWwindow *glfwWindow = nullptr;
|
||||
static vr::VROverlayHandle_t overlayMainHandle = 0, overlayThumbnailHandle = 0;
|
||||
static GLuint fboHandle = 0, fboTextureHandle = 0;
|
||||
static int fboTextureWidth = 0, fboTextureHeight = 0;
|
||||
|
||||
static char cwd[MAX_PATH];
|
||||
|
||||
void CreateGLFWWindow()
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, false);
|
||||
|
||||
glfwWindow = glfwCreateWindow(1280, 800, "OpenVR-SpaceCalibrator", NULL, NULL);
|
||||
fboTextureWidth = 1200;
|
||||
fboTextureHeight = 800;
|
||||
|
||||
glfwWindow = glfwCreateWindow(fboTextureWidth, fboTextureHeight, "OpenVR-SpaceCalibrator", NULL, NULL);
|
||||
if (!glfwWindow)
|
||||
throw std::runtime_error("Failed to create window");
|
||||
|
||||
@@ -49,6 +65,8 @@ void CreateGLFWWindow()
|
||||
glfwSwapInterval(1);
|
||||
gl3wInit();
|
||||
|
||||
glfwIconifyWindow(glfwWindow);
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
@@ -57,48 +75,256 @@ void CreateGLFWWindow()
|
||||
io.Fonts->AddFontFromMemoryCompressedTTF(DroidSans_compressed_data, DroidSans_compressed_size, 24.0f);
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(glfwWindow, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 150");
|
||||
ImGui_ImplOpenGL3_Init("#version 330");
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
glGenTextures(1, &fboTextureHandle);
|
||||
glBindTexture(GL_TEXTURE_2D, fboTextureHandle);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fboTextureWidth, fboTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glGenFramebuffers(1, &fboHandle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboHandle);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextureHandle, 0);
|
||||
|
||||
GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
|
||||
glDrawBuffers(1, drawBuffers);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
throw std::runtime_error("OpenGL framebuffer incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
void TryCreateVROverlay()
|
||||
{
|
||||
if (overlayMainHandle || !vr::VROverlay())
|
||||
return;
|
||||
|
||||
vr::VROverlayError error = vr::VROverlay()->CreateDashboardOverlay(
|
||||
"pushrax.SpaceCalibrator", "Space Cal",
|
||||
&overlayMainHandle, &overlayThumbnailHandle
|
||||
);
|
||||
|
||||
if (error == vr::VROverlayError_KeyInUse)
|
||||
{
|
||||
throw std::runtime_error("Another instance of OpenVR Space Calibrator is already running");
|
||||
}
|
||||
else if (error != vr::VROverlayError_None)
|
||||
{
|
||||
throw std::runtime_error("Error creating VR overlay: " + std::string(vr::VROverlay()->GetOverlayErrorNameFromEnum(error)));
|
||||
}
|
||||
|
||||
vr::VROverlay()->SetOverlayWidthInMeters(overlayMainHandle, 3.0f);
|
||||
vr::VROverlay()->SetOverlayInputMethod(overlayMainHandle, vr::VROverlayInputMethod_Mouse);
|
||||
vr::VROverlay()->SetOverlayFlag(overlayMainHandle, vr::VROverlayFlags_SendVRDiscreteScrollEvents, true);
|
||||
|
||||
std::string iconPath = cwd;
|
||||
iconPath += "\\icon.png";
|
||||
vr::VROverlay()->SetOverlayFromFile(overlayThumbnailHandle, iconPath.c_str());
|
||||
}
|
||||
|
||||
void ActivateMultipleDrivers()
|
||||
{
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
bool enabled = vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool, &vrSettingsError);
|
||||
|
||||
if (vrSettingsError != vr::VRSettingsError_None)
|
||||
{
|
||||
std::string err = "Could not read \"" + std::string(vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool) + "\" setting: "
|
||||
+ vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool, true, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None)
|
||||
{
|
||||
std::string err = "Could not set \"" + std::string(vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool) + "\" setting: "
|
||||
+ vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
std::cerr << "Enabled \"" << vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool << "\" setting" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\"" << vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool << "\" setting previously enabled" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InitVR()
|
||||
{
|
||||
auto initError = vr::VRInitError_None;
|
||||
vr::VR_Init(&initError, vr::VRApplication_Other);
|
||||
if (initError != vr::VRInitError_None)
|
||||
{
|
||||
auto error = vr::VR_GetVRInitErrorAsEnglishDescription(initError);
|
||||
throw std::runtime_error("OpenVR error:" + std::string(error));
|
||||
}
|
||||
|
||||
if (!vr::VR_IsInterfaceVersionValid(vr::IVRSystem_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSystem_Version");
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVRSettings_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSettings_Version");
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVROverlay_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVROverlay_Version");
|
||||
}
|
||||
|
||||
ActivateMultipleDrivers();
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
{
|
||||
while (!glfwWindowShouldClose(glfwWindow))
|
||||
{
|
||||
TryCreateVROverlay();
|
||||
|
||||
double time = glfwGetTime();
|
||||
CalibrationTick(time);
|
||||
|
||||
bool dashboardVisible = false;
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(glfwWindow, &width, &height);
|
||||
|
||||
if (overlayMainHandle && vr::VROverlay())
|
||||
{
|
||||
auto &io = ImGui::GetIO();
|
||||
dashboardVisible = vr::VROverlay()->IsActiveDashboardOverlay(overlayMainHandle);
|
||||
|
||||
static bool keyboardOpen = false, keyboardJustClosed = false;
|
||||
|
||||
// After closing the keyboard, this code waits one frame for ImGui to pick up the new text from SetActiveText
|
||||
// before clearing the active widget. Then it waits another frame before allowing the keyboard to open again,
|
||||
// otherwise it will do so instantly since WantTextInput is still true on the second frame.
|
||||
if (keyboardJustClosed && keyboardOpen)
|
||||
{
|
||||
ImGui::ClearActiveID();
|
||||
keyboardOpen = false;
|
||||
}
|
||||
else if (keyboardJustClosed)
|
||||
{
|
||||
keyboardJustClosed = false;
|
||||
}
|
||||
else if (!io.WantTextInput)
|
||||
{
|
||||
// User might close the keyboard without hitting Done, so we unset the flag to allow it to open again.
|
||||
keyboardOpen = false;
|
||||
}
|
||||
else if (io.WantTextInput && !keyboardOpen && !keyboardJustClosed)
|
||||
{
|
||||
char buf[0x400];
|
||||
ImGui::GetActiveText(buf, sizeof buf);
|
||||
buf[0x3ff] = 0;
|
||||
uint32_t unFlags = 0; // EKeyboardFlags
|
||||
|
||||
vr::VROverlay()->ShowKeyboardForOverlay(
|
||||
overlayMainHandle, vr::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine,
|
||||
unFlags, "Space Calibrator Overlay", sizeof buf, buf, 0
|
||||
);
|
||||
keyboardOpen = true;
|
||||
}
|
||||
|
||||
vr::VREvent_t vrEvent;
|
||||
while (vr::VROverlay()->PollNextOverlayEvent(overlayMainHandle, &vrEvent, sizeof(vrEvent)))
|
||||
{
|
||||
switch (vrEvent.eventType) {
|
||||
case vr::VREvent_MouseMove:
|
||||
io.MousePos.x = vrEvent.data.mouse.x;
|
||||
io.MousePos.y = vrEvent.data.mouse.y;
|
||||
break;
|
||||
case vr::VREvent_MouseButtonDown:
|
||||
io.MouseDown[vrEvent.data.mouse.button == vr::VRMouseButton_Left ? 0 : 1] = true;
|
||||
break;
|
||||
case vr::VREvent_MouseButtonUp:
|
||||
io.MouseDown[vrEvent.data.mouse.button == vr::VRMouseButton_Left ? 0 : 1] = false;
|
||||
break;
|
||||
case vr::VREvent_ScrollDiscrete:
|
||||
io.MouseWheelH += vrEvent.data.scroll.xdelta * 360.0f * 8.0f;
|
||||
io.MouseWheel += vrEvent.data.scroll.ydelta * 360.0f * 8.0f;
|
||||
break;
|
||||
case vr::VREvent_KeyboardDone: {
|
||||
char buf[0x400];
|
||||
vr::VROverlay()->GetKeyboardText(buf, sizeof buf);
|
||||
ImGui::SetActiveText(buf, sizeof buf);
|
||||
keyboardJustClosed = true;
|
||||
break;
|
||||
}
|
||||
case vr::VREvent_Quit:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::GetIO().DisplaySize = ImVec2((float) fboTextureWidth, (float) fboTextureHeight);
|
||||
|
||||
ImGui_ImplGlfw_SetReadMouseFromGlfw(!dashboardVisible);
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
BuildMainWindow();
|
||||
BuildMainWindow(dashboardVisible);
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboHandle);
|
||||
glViewport(0, 0, fboTextureWidth, fboTextureHeight);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
glfwSwapBuffers(glfwWindow);
|
||||
glfwWaitEventsTimeout(CalCtx.wantedUpdateInterval);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
if (width && height)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboHandle);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glfwSwapBuffers(glfwWindow);
|
||||
}
|
||||
|
||||
if (dashboardVisible)
|
||||
{
|
||||
vr::Texture_t vrTex;
|
||||
vrTex.eType = vr::TextureType_OpenGL;
|
||||
vrTex.eColorSpace = vr::ColorSpace_Linear;
|
||||
|
||||
vrTex.handle = (void *)
|
||||
#if defined _WIN64 || defined _LP64
|
||||
(uint64_t)
|
||||
#endif
|
||||
fboTextureHandle;
|
||||
|
||||
vr::HmdVector2_t mouseScale = { (float) fboTextureWidth, (float) fboTextureHeight };
|
||||
|
||||
vr::VROverlay()->SetOverlayTexture(overlayMainHandle, &vrTex);
|
||||
vr::VROverlay()->SetOverlayMouseScale(overlayMainHandle, &mouseScale);
|
||||
}
|
||||
|
||||
const double dashboardInterval = 1.0 / 90.0; // fps
|
||||
double waitEventsTimeout = CalCtx.wantedUpdateInterval;
|
||||
|
||||
if (dashboardVisible && waitEventsTimeout > dashboardInterval)
|
||||
waitEventsTimeout = dashboardInterval;
|
||||
|
||||
glfwWaitEventsTimeout(waitEventsTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hPrevInstance);
|
||||
UNREFERENCED_PARAMETER(lpCmdLine);
|
||||
_getcwd(cwd, MAX_PATH);
|
||||
HandleCommandLine(lpCmdLine);
|
||||
//CreateConsole();
|
||||
|
||||
if (!glfwInit())
|
||||
@@ -112,8 +338,21 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
try {
|
||||
InitVR();
|
||||
CreateGLFWWindow();
|
||||
InitCalibrator();
|
||||
LoadProfile(CalCtx);
|
||||
RunLoop();
|
||||
|
||||
vr::VR_Shutdown();
|
||||
|
||||
if (fboHandle)
|
||||
glDeleteFramebuffers(1, &fboHandle);
|
||||
|
||||
if (fboTextureHandle)
|
||||
glDeleteTextures(1, &fboTextureHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
@@ -128,4 +367,112 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleCommandLine(LPWSTR lpCmdLine)
|
||||
{
|
||||
if (lstrcmp(lpCmdLine, L"-openvrpath") == 0)
|
||||
{
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
char cruntimePath[MAX_PATH] = { 0 };
|
||||
unsigned int pathLen;
|
||||
vr::VR_GetRuntimePath(cruntimePath, MAX_PATH, &pathLen);
|
||||
|
||||
printf("%s", cruntimePath);
|
||||
vr::VR_Shutdown();
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
else if (lstrcmp(lpCmdLine, L"-installmanifest") == 0)
|
||||
{
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
if (vr::VRApplications()->IsApplicationInstalled(OPENVR_APPLICATION_KEY))
|
||||
{
|
||||
char oldWd[MAX_PATH] = { 0 };
|
||||
auto vrAppErr = vr::VRApplicationError_None;
|
||||
vr::VRApplications()->GetApplicationPropertyString(OPENVR_APPLICATION_KEY, vr::VRApplicationProperty_WorkingDirectory_String, oldWd, MAX_PATH, &vrAppErr);
|
||||
if (vrAppErr != vr::VRApplicationError_None)
|
||||
{
|
||||
fprintf(stderr, "Failed to get old working dir, skipping removal: %s\n", vr::VRApplications()->GetApplicationsErrorNameFromEnum(vrAppErr));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string manifestPath = oldWd;
|
||||
manifestPath += "\\manifest.vrmanifest";
|
||||
std::cout << "Removing old manifest path: " << manifestPath << std::endl;
|
||||
vr::VRApplications()->RemoveApplicationManifest(manifestPath.c_str());
|
||||
}
|
||||
}
|
||||
std::string manifestPath = cwd;
|
||||
manifestPath += "\\manifest.vrmanifest";
|
||||
std::cout << "Adding manifest path: " << manifestPath << std::endl;
|
||||
auto vrAppErr = vr::VRApplications()->AddApplicationManifest(manifestPath.c_str());
|
||||
if (vrAppErr != vr::VRApplicationError_None)
|
||||
{
|
||||
fprintf(stderr, "Failed to add manifest: %s\n", vr::VRApplications()->GetApplicationsErrorNameFromEnum(vrAppErr));
|
||||
}
|
||||
else
|
||||
{
|
||||
vr::VRApplications()->SetApplicationAutoLaunch(OPENVR_APPLICATION_KEY, true);
|
||||
}
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
else if (lstrcmp(lpCmdLine, L"-removemanifest") == 0)
|
||||
{
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
if (vr::VRApplications()->IsApplicationInstalled(OPENVR_APPLICATION_KEY))
|
||||
{
|
||||
std::string manifestPath = cwd;
|
||||
manifestPath += "\\manifest.vrmanifest";
|
||||
std::cout << "Removing manifest path: " << manifestPath << std::endl;
|
||||
vr::VRApplications()->RemoveApplicationManifest(manifestPath.c_str());
|
||||
}
|
||||
vr::VR_Shutdown();
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
else if (lstrcmp(lpCmdLine, L"-activatemultipledrivers") == 0)
|
||||
{
|
||||
int ret = -2;
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
try
|
||||
{
|
||||
ActivateMultipleDrivers();
|
||||
ret = 0;
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
}
|
||||
vr::VR_Shutdown();
|
||||
exit(ret);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 70 KiB |
@@ -55,12 +55,12 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\glfw\include;..\lib\openvr;..\lib\boost_1_63_0;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\lib\gl3w\include;..\lib\glfw\include;..\lib\openvr;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\glfw\lib-vc2015;..\lib\boost_1_63_0\lib64-msvc-14.0;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\lib\glfw\lib-vc2015;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>openvr_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -73,27 +73,22 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\gl3w\include;..\lib\glfw\include;..\lib\openvr;..\lib\boost_1_63_0;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\lib\gl3w\include;..\lib\glfw\include;..\lib\openvr;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\glfw\lib-vc2015;..\lib\boost_1_63_0\lib64-msvc-14.0;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\lib\glfw\lib-vc2015;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glfw3.lib;openvr_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\ipc_protocol.h" />
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator.h" />
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator_types.h" />
|
||||
<ClInclude Include="Calibration.h" />
|
||||
<ClInclude Include="Configuration.h" />
|
||||
<ClInclude Include="EmbeddedFiles.h" />
|
||||
<ClInclude Include="IPCClient.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="UserInterface.h" />
|
||||
@@ -117,15 +112,12 @@
|
||||
<ClCompile Include="..\lib\imgui\imgui_impl_opengl3.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\lib_vrinputemulator\vrinputemulator.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Calibration.cpp" />
|
||||
<ClCompile Include="Configuration.cpp" />
|
||||
<ClCompile Include="EmbeddedFiles.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPCClient.cpp" />
|
||||
<ClCompile Include="OpenVR-SpaceCalibrator.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
<UniqueIdentifier>{d156ae5c-9fe6-41f0-a34e-333dc7a6b2f8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
@@ -33,15 +30,6 @@
|
||||
<ClInclude Include="Calibration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\ipc_protocol.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EmbeddedFiles.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -51,20 +39,17 @@
|
||||
<ClInclude Include="Configuration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPCClient.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OpenVR-SpaceCalibrator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Calibration.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\lib_vrinputemulator\vrinputemulator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui.cpp">
|
||||
<Filter>Source Files\ImGui</Filter>
|
||||
</ClCompile>
|
||||
@@ -92,6 +77,12 @@
|
||||
<ClCompile Include="Configuration.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPCClient.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OpenVR-SpaceCalibrator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="small.ico">
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <algorithm>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#define VERSION_STRING "0.9.0"
|
||||
|
||||
struct VRDevice
|
||||
{
|
||||
int id = -1;
|
||||
@@ -32,7 +34,7 @@ void BuildSystemSelection(const VRState &state);
|
||||
void BuildDeviceSelections(const VRState &state);
|
||||
void BuildProfileEditor();
|
||||
|
||||
void BuildMainWindow()
|
||||
void BuildMainWindow(bool runningInOverlay)
|
||||
{
|
||||
ImGuiWindowFlags windowFlags =
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
@@ -42,7 +44,7 @@ void BuildMainWindow()
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(io.DisplaySize, ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(io.DisplaySize, ImGuiSetCond_Always);
|
||||
|
||||
if (!ImGui::Begin("MainWindow", nullptr, windowFlags))
|
||||
{
|
||||
@@ -60,15 +62,20 @@ void BuildMainWindow()
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
{
|
||||
float width = ImGui::GetWindowContentRegionWidth();
|
||||
float scale = 1.0f;
|
||||
if (CalCtx.validProfile)
|
||||
if (CalCtx.validProfile && !CalCtx.enabled)
|
||||
{
|
||||
width -= style.FramePadding.x * 2.0f;
|
||||
scale = 2.0f / 3.0f;
|
||||
ImGui::TextColored(ImColor(0.8f, 0.2f, 0.2f), "Reference (%s) HMD not detected, profile disabled", CalCtx.referenceTrackingSystem.c_str());
|
||||
ImGui::Text("");
|
||||
}
|
||||
|
||||
if (ImGui::Button("Start New Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
float width = ImGui::GetWindowContentRegionWidth(), scale = 1.0f;
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
width -= style.FramePadding.x * 4.0f;
|
||||
scale = 1.0f / 3.0f;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Start Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
ImGui::OpenPopup("Calibration Progress");
|
||||
StartCalibration();
|
||||
@@ -77,10 +84,46 @@ void BuildMainWindow()
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Edit Calibration", ImVec2(width / 3.0f, ImGui::GetTextLineHeight() * 2)))
|
||||
if (ImGui::Button("Edit Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
CalCtx.state = CalibrationState::Editing;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
CalCtx.Clear();
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
}
|
||||
|
||||
width = ImGui::GetWindowContentRegionWidth();
|
||||
scale = 1.0f;
|
||||
if (CalCtx.chaperone.valid)
|
||||
{
|
||||
width -= style.FramePadding.x * 2.0f;
|
||||
scale = 0.5;
|
||||
}
|
||||
|
||||
ImGui::Text("");
|
||||
if (ImGui::Button("Copy Chaperone Bounds to profile", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
LoadChaperoneBounds();
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
|
||||
if (CalCtx.chaperone.valid)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Paste Chaperone Bounds", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
ApplyChaperoneBounds();
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox(" Paste Chaperone Bounds automatically when geometry resets", &CalCtx.chaperone.autoApply))
|
||||
{
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CalCtx.state == CalibrationState::Editing)
|
||||
@@ -99,7 +142,7 @@ void BuildMainWindow()
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x - 40.0f, io.DisplaySize.y - 40.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x - 40.0f, io.DisplaySize.y - 40.0f), ImGuiSetCond_Always);
|
||||
if (ImGui::BeginPopupModal("Calibration Progress", nullptr, windowFlags))
|
||||
{
|
||||
ImGui::TextWrapped(CalCtx.messages.c_str());
|
||||
@@ -114,9 +157,14 @@ void BuildMainWindow()
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(ImGui::GetWindowWidth() - 60.0f, ImGui::GetWindowHeight() - ImGui::GetItemsLineHeightWithSpacing()));
|
||||
ImGui::BeginChild("version stuff", ImVec2(60.0f, ImGui::GetItemsLineHeightWithSpacing() * 2), false);
|
||||
ImGui::Text("v0.5");
|
||||
ImGui::SetNextWindowPos(ImVec2(10.0f, ImGui::GetWindowHeight() - ImGui::GetItemsLineHeightWithSpacing()));
|
||||
ImGui::BeginChild("bottom line", ImVec2(ImGui::GetWindowWidth() - 20.0f, ImGui::GetItemsLineHeightWithSpacing() * 2), false);
|
||||
ImGui::Text("OpenVR Space Calibrator v" VERSION_STRING " - by tach/pushrax");
|
||||
if (runningInOverlay)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("- close VR overlay to use mouse");
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void BuildMainWindow();
|
||||
void BuildMainWindow(bool runningInOverlay);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"source" : "builtin",
|
||||
"applications": [{
|
||||
"app_key": "pushrax.SpaceCalibrator",
|
||||
"launch_type": "binary",
|
||||
"binary_path_windows": "OpenVR-SpaceCalibrator.exe",
|
||||
"is_dashboard_overlay": true,
|
||||
|
||||
"strings": {
|
||||
"en_us": {
|
||||
"name": "Space Calibrator",
|
||||
"description": "OpenVR Space Calibrator Overlay"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"alwaysActivate": true,
|
||||
"name" : "01spacecalibrator",
|
||||
"directory" : "",
|
||||
"resourceOnly" : false
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"jsonid" : "vrresources",
|
||||
"statusicons" : {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"driver_01spacecalibrator" : {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "Hooking.h"
|
||||
|
||||
std::map<std::string, IHook *> IHook::hooks;
|
||||
|
||||
bool IHook::Exists(const std::string &name)
|
||||
{
|
||||
return hooks.find(name) != hooks.end();
|
||||
}
|
||||
|
||||
void IHook::Register(IHook *hook)
|
||||
{
|
||||
hooks[hook->name] = hook;
|
||||
}
|
||||
|
||||
void IHook::Unregister(IHook *hook)
|
||||
{
|
||||
hooks.erase(hook->name);
|
||||
}
|
||||
|
||||
void IHook::DestroyAll()
|
||||
{
|
||||
for (auto &hook : hooks)
|
||||
{
|
||||
hook.second->Destroy();
|
||||
}
|
||||
hooks.clear();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "Logging.h"
|
||||
#include <MinHook.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class IHook
|
||||
{
|
||||
public:
|
||||
const std::string name;
|
||||
|
||||
IHook(const std::string &name) : name(name) { }
|
||||
virtual ~IHook() { }
|
||||
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
static bool Exists(const std::string &name);
|
||||
static void Register(IHook *hook);
|
||||
static void Unregister(IHook *hook);
|
||||
static void DestroyAll();
|
||||
|
||||
private:
|
||||
static std::map<std::string, IHook *> hooks;
|
||||
};
|
||||
|
||||
template<class FuncType> class Hook : public IHook
|
||||
{
|
||||
public:
|
||||
FuncType originalFunc = nullptr;
|
||||
Hook(const std::string &name) : IHook(name) { }
|
||||
|
||||
bool CreateHookInObjectVTable(void *object, int vtableOffset, void *detourFunction)
|
||||
{
|
||||
// For virtual objects, VC++ adds a pointer to the vtable as the first member.
|
||||
// To access the vtable, we simply dereference the object.
|
||||
void **vtable = *((void ***)object);
|
||||
|
||||
// The vtable itself is an array of pointers to member functions,
|
||||
// in the order they were declared in.
|
||||
targetFunc = vtable[vtableOffset];
|
||||
|
||||
auto err = MH_CreateHook(targetFunc, detourFunction, (LPVOID *)&originalFunc);
|
||||
if (err != MH_OK)
|
||||
{
|
||||
LOG("Failed to create hook for %s, error: %s", name.c_str(), MH_StatusToString(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = MH_EnableHook(targetFunc);
|
||||
if (err != MH_OK)
|
||||
{
|
||||
LOG("Failed to enable hook for %s, error: %s", name.c_str(), MH_StatusToString(err));
|
||||
MH_RemoveHook(targetFunc);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG("Enabled hook for %s", name.c_str());
|
||||
enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
MH_RemoveHook(targetFunc);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool enabled = false;
|
||||
void* targetFunc = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,220 @@
|
||||
#include "IPCServer.h"
|
||||
#include "Logging.h"
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
|
||||
void IPCServer::HandleRequest(const protocol::Request &request, protocol::Response &response)
|
||||
{
|
||||
switch (request.type)
|
||||
{
|
||||
case protocol::RequestHandshake:
|
||||
response.type = protocol::ResponseHandshake;
|
||||
response.protocol.version = protocol::Version;
|
||||
break;
|
||||
|
||||
case protocol::RequestSetDeviceTransform:
|
||||
driver->SetDeviceTransform(request.setDeviceTransform);
|
||||
response.type = protocol::ResponseSuccess;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG("Invalid IPC request: %d", request.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IPCServer::~IPCServer()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void IPCServer::Run()
|
||||
{
|
||||
mainThread = std::thread(RunThread, this);
|
||||
}
|
||||
|
||||
void IPCServer::Stop()
|
||||
{
|
||||
TRACE("IPCServer::Stop()");
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
stop = true;
|
||||
SetEvent(connectEvent);
|
||||
mainThread.join();
|
||||
running = false;
|
||||
TRACE("IPCServer::Stop() finished");
|
||||
}
|
||||
|
||||
IPCServer::PipeInstance *IPCServer::CreatePipeInstance(HANDLE pipe)
|
||||
{
|
||||
auto pipeInst = new PipeInstance;
|
||||
pipeInst->pipe = pipe;
|
||||
pipeInst->server = this;
|
||||
pipes.insert(pipeInst);
|
||||
return pipeInst;
|
||||
}
|
||||
|
||||
void IPCServer::ClosePipeInstance(PipeInstance *pipeInst)
|
||||
{
|
||||
DisconnectNamedPipe(pipeInst->pipe);
|
||||
CloseHandle(pipeInst->pipe);
|
||||
pipes.erase(pipeInst);
|
||||
delete pipeInst;
|
||||
}
|
||||
|
||||
void IPCServer::RunThread(IPCServer *_this)
|
||||
{
|
||||
_this->running = true;
|
||||
LPTSTR pipeName = TEXT(OPENVR_SPACECALIBRATOR_PIPE_NAME);
|
||||
|
||||
HANDLE connectEvent = _this->connectEvent = CreateEvent(0, TRUE, TRUE, 0);
|
||||
if (!connectEvent)
|
||||
{
|
||||
LOG("CreateEvent failed in RunThread. Error: %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
OVERLAPPED connectOverlap;
|
||||
connectOverlap.hEvent = connectEvent;
|
||||
|
||||
HANDLE nextPipe;
|
||||
BOOL connectPending = CreateAndConnectInstance(&connectOverlap, nextPipe);
|
||||
|
||||
while (!_this->stop)
|
||||
{
|
||||
DWORD wait = WaitForSingleObjectEx(connectEvent, INFINITE, TRUE);
|
||||
|
||||
if (_this->stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (wait == 0)
|
||||
{
|
||||
// When connectPending is false, the last call to CreateAndConnectInstance
|
||||
// picked up a connected client and triggered this event, so we can simply
|
||||
// create a new pipe instance for it. If true, the client was still pending
|
||||
// connection when CreateAndConnectInstance returned, so this event was triggered
|
||||
// internally and we need to flush out the result, or something like that.
|
||||
if (connectPending)
|
||||
{
|
||||
DWORD bytesConnect;
|
||||
BOOL success = GetOverlappedResult(nextPipe, &connectOverlap, &bytesConnect, FALSE);
|
||||
if (!success)
|
||||
{
|
||||
LOG("GetOverlappedResult failed in RunThread. Error: %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("IPC client connected");
|
||||
|
||||
auto pipeInst = _this->CreatePipeInstance(nextPipe);
|
||||
CompletedWriteCallback(0, sizeof protocol::Response, (LPOVERLAPPED) pipeInst);
|
||||
|
||||
connectPending = CreateAndConnectInstance(&connectOverlap, nextPipe);
|
||||
}
|
||||
else if (wait != WAIT_IO_COMPLETION)
|
||||
{
|
||||
printf("WaitForSingleObjectEx failed in RunThread. Error %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pipeInst : _this->pipes)
|
||||
{
|
||||
_this->ClosePipeInstance(pipeInst);
|
||||
}
|
||||
_this->pipes.clear();
|
||||
}
|
||||
|
||||
BOOL IPCServer::CreateAndConnectInstance(LPOVERLAPPED overlap, HANDLE &pipe)
|
||||
{
|
||||
pipe = CreateNamedPipe(
|
||||
TEXT(OPENVR_SPACECALIBRATOR_PIPE_NAME),
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
sizeof protocol::Request,
|
||||
sizeof protocol::Response,
|
||||
1000,
|
||||
0
|
||||
);
|
||||
|
||||
if (pipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG("CreateNamedPipe failed. Error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ConnectNamedPipe(pipe, overlap);
|
||||
|
||||
switch(GetLastError())
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
// Mark a pending connection by returning true, and when the connection
|
||||
// completes an event will trigger automatically.
|
||||
return TRUE;
|
||||
|
||||
case ERROR_PIPE_CONNECTED:
|
||||
// Signal the event loop that a client is connected.
|
||||
if (SetEvent(overlap->hEvent))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LOG("ConnectNamedPipe failed. Error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void IPCServer::CompletedReadCallback(DWORD err, DWORD bytesRead, LPOVERLAPPED overlap)
|
||||
{
|
||||
PipeInstance *pipeInst = (PipeInstance *) overlap;
|
||||
BOOL success = FALSE;
|
||||
|
||||
if (err == 0 && bytesRead > 0)
|
||||
{
|
||||
pipeInst->server->HandleRequest(pipeInst->request, pipeInst->response);
|
||||
success = WriteFileEx(
|
||||
pipeInst->pipe,
|
||||
&pipeInst->response,
|
||||
sizeof protocol::Response,
|
||||
overlap,
|
||||
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteCallback
|
||||
);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
LOG("IPC client disconnecting normally");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("IPC client disconnecting due to error (via CompletedReadCallback), error: %d, bytesRead: %d", err, bytesRead);
|
||||
}
|
||||
pipeInst->server->ClosePipeInstance(pipeInst);
|
||||
}
|
||||
}
|
||||
|
||||
void IPCServer::CompletedWriteCallback(DWORD err, DWORD bytesWritten, LPOVERLAPPED overlap)
|
||||
{
|
||||
PipeInstance *pipeInst = (PipeInstance *) overlap;
|
||||
BOOL success = FALSE;
|
||||
|
||||
if (err == 0 && bytesWritten == sizeof protocol::Response)
|
||||
{
|
||||
success = ReadFileEx(
|
||||
pipeInst->pipe,
|
||||
&pipeInst->request,
|
||||
sizeof protocol::Request,
|
||||
overlap,
|
||||
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadCallback
|
||||
);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
LOG("IPC client disconnecting due to error (via CompletedWriteCallback), error: %d, bytesWritten: %d", err, bytesWritten);
|
||||
pipeInst->server->ClosePipeInstance(pipeInst);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Protocol.h"
|
||||
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class ServerTrackedDeviceProvider;
|
||||
|
||||
class IPCServer
|
||||
{
|
||||
public:
|
||||
IPCServer(ServerTrackedDeviceProvider *driver) : driver(driver) { }
|
||||
~IPCServer();
|
||||
|
||||
void Run();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void HandleRequest(const protocol::Request &request, protocol::Response &response);
|
||||
|
||||
struct PipeInstance
|
||||
{
|
||||
OVERLAPPED overlap; // Used by the API
|
||||
HANDLE pipe;
|
||||
IPCServer *server;
|
||||
|
||||
protocol::Request request;
|
||||
protocol::Response response;
|
||||
};
|
||||
|
||||
PipeInstance *CreatePipeInstance(HANDLE pipe);
|
||||
void ClosePipeInstance(PipeInstance *pipeInst);
|
||||
|
||||
static void RunThread(IPCServer *_this);
|
||||
static BOOL CreateAndConnectInstance(LPOVERLAPPED overlap, HANDLE &pipe);
|
||||
static void WINAPI CompletedReadCallback(DWORD err, DWORD bytesRead, LPOVERLAPPED overlap);
|
||||
static void WINAPI CompletedWriteCallback(DWORD err, DWORD bytesWritten, LPOVERLAPPED overlap);
|
||||
|
||||
std::thread mainThread;
|
||||
|
||||
bool running = false;
|
||||
bool stop = false;
|
||||
|
||||
std::set<PipeInstance *> pipes;
|
||||
HANDLE connectEvent;
|
||||
|
||||
ServerTrackedDeviceProvider *driver;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "Logging.h"
|
||||
#include "Hooking.h"
|
||||
#include "InterfaceHookInjector.h"
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
|
||||
static ServerTrackedDeviceProvider *Driver = nullptr;
|
||||
|
||||
static Hook<void*(*)(vr::IVRDriverContext *, const char *, vr::EVRInitError *)>
|
||||
GetGenericInterfaceHook("IVRDriverContext::GetGenericInterface");
|
||||
|
||||
static Hook<void(*)(vr::IVRServerDriverHost *, uint32_t, const vr::DriverPose_t &, uint32_t)>
|
||||
TrackedDevicePoseUpdatedHook("IVRServerDriverHost005::TrackedDevicePoseUpdated");
|
||||
|
||||
static void DetourTrackedDevicePoseUpdated(vr::IVRServerDriverHost *_this, uint32_t unWhichDevice, const vr::DriverPose_t &newPose, uint32_t unPoseStructSize)
|
||||
{
|
||||
//TRACE("ServerTrackedDeviceProvider::DetourTrackedDevicePoseUpdated(%d)", unWhichDevice);
|
||||
auto pose = newPose;
|
||||
if (Driver->HandleDevicePoseUpdated(unWhichDevice, pose))
|
||||
{
|
||||
TrackedDevicePoseUpdatedHook.originalFunc(_this, unWhichDevice, pose, unPoseStructSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void *DetourGetGenericInterface(vr::IVRDriverContext *_this, const char *pchInterfaceVersion, vr::EVRInitError *peError)
|
||||
{
|
||||
TRACE("ServerTrackedDeviceProvider::DetourGetGenericInterface(%s)", pchInterfaceVersion);
|
||||
auto originalInterface = GetGenericInterfaceHook.originalFunc(_this, pchInterfaceVersion, peError);
|
||||
|
||||
std::string iface(pchInterfaceVersion);
|
||||
if (iface == "IVRServerDriverHost_005")
|
||||
{
|
||||
if (!IHook::Exists(TrackedDevicePoseUpdatedHook.name))
|
||||
{
|
||||
TrackedDevicePoseUpdatedHook.CreateHookInObjectVTable(originalInterface, 1, &DetourTrackedDevicePoseUpdated);
|
||||
IHook::Register(&TrackedDevicePoseUpdatedHook);
|
||||
}
|
||||
}
|
||||
|
||||
return originalInterface;
|
||||
}
|
||||
|
||||
void InjectHooks(ServerTrackedDeviceProvider *driver, vr::IVRDriverContext *pDriverContext)
|
||||
{
|
||||
Driver = driver;
|
||||
|
||||
auto err = MH_Initialize();
|
||||
if (err == MH_OK)
|
||||
{
|
||||
GetGenericInterfaceHook.CreateHookInObjectVTable(pDriverContext, 0, &DetourGetGenericInterface);
|
||||
IHook::Register(&GetGenericInterfaceHook);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("MH_Initialize error: %s", MH_StatusToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
void DisableHooks()
|
||||
{
|
||||
IHook::DestroyAll();
|
||||
MH_Uninitialize();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvr_driver.h>
|
||||
|
||||
class ServerTrackedDeviceProvider;
|
||||
|
||||
static void DetourTrackedDevicePoseUpdated(vr::IVRServerDriverHost * _this, uint32_t unWhichDevice, const vr::DriverPose_t & newPose, uint32_t unPoseStructSize);
|
||||
|
||||
void InjectHooks(ServerTrackedDeviceProvider *driver, vr::IVRDriverContext *pDriverContext);
|
||||
void DisableHooks();
|
||||
@@ -0,0 +1,28 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include "Logging.h"
|
||||
#include <chrono>
|
||||
|
||||
FILE *LogFile;
|
||||
|
||||
void OpenLogFile()
|
||||
{
|
||||
LogFile = fopen("space_calibrator_driver.log", "a");
|
||||
if (LogFile == nullptr)
|
||||
{
|
||||
LogFile = stderr;
|
||||
}
|
||||
}
|
||||
|
||||
tm TimeForLog()
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto nowTime = std::chrono::system_clock::to_time_t(now);
|
||||
tm value;
|
||||
auto tm = localtime_s(&value, &nowTime);
|
||||
return value;
|
||||
}
|
||||
|
||||
void LogFlush()
|
||||
{
|
||||
fflush(LogFile);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
extern FILE *LogFile;
|
||||
|
||||
void OpenLogFile();
|
||||
tm TimeForLog();
|
||||
void LogFlush();
|
||||
|
||||
#ifndef LOG
|
||||
#define LOG(fmt, ...) do { \
|
||||
tm logNow = TimeForLog(); \
|
||||
fprintf(LogFile, "[%02d:%02d:%02d] " fmt "\n", logNow.tm_hour, logNow.tm_min, logNow.tm_sec, __VA_ARGS__); \
|
||||
LogFlush(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define TRACE(...) {}
|
||||
|
||||
#ifndef TRACE
|
||||
#define TRACE LOG
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "OpenVR-SpaceCalibratorDriver.h"
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
#include "VRWatchdogProvider.h"
|
||||
#include "Logging.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <openvr_driver.h>
|
||||
|
||||
OPENVRSPACECALIBRATORDRIVER_API void *HmdDriverFactory(const char *pInterfaceName, int *pReturnCode)
|
||||
{
|
||||
TRACE("HmdDriverFactory(%s)", pInterfaceName);
|
||||
|
||||
static ServerTrackedDeviceProvider server;
|
||||
static VRWatchdogProvider watchdog;
|
||||
|
||||
if (std::strcmp(vr::IServerTrackedDeviceProvider_Version, pInterfaceName) == 0)
|
||||
{
|
||||
return &server;
|
||||
}
|
||||
else if (std::strcmp(vr::IVRWatchdogProvider_Version, pInterfaceName) == 0)
|
||||
{
|
||||
return &watchdog;
|
||||
}
|
||||
|
||||
if (pReturnCode)
|
||||
{
|
||||
*pReturnCode = vr::VRInitError_Init_InterfaceNotFound;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef OPENVRSPACECALIBRATORDRIVER_EXPORTS
|
||||
#define OPENVRSPACECALIBRATORDRIVER_API extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define OPENVRSPACECALIBRATORDRIVER_API extern "C" __declspec(dllimport)
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>OpenVRSpaceCalibratorDriver</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>driver_01spacecalibrator</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>driver_01spacecalibrator</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;OPENVRSPACECALIBRATORDRIVER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\MinHook\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\MinHook\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>libMinHook-x64-v140-mdd.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;OPENVRSPACECALIBRATORDRIVER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\MinHook\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\MinHook\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>libMinHook-x64-v140-md.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Protocol.h" />
|
||||
<ClInclude Include="Hooking.h" />
|
||||
<ClInclude Include="InterfaceHookInjector.h" />
|
||||
<ClInclude Include="IPCServer.h" />
|
||||
<ClInclude Include="Logging.h" />
|
||||
<ClInclude Include="OpenVR-SpaceCalibratorDriver.h" />
|
||||
<ClInclude Include="ServerTrackedDeviceProvider.h" />
|
||||
<ClInclude Include="VRWatchdogProvider.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Hooking.cpp" />
|
||||
<ClCompile Include="InterfaceHookInjector.cpp" />
|
||||
<ClCompile Include="IPCServer.cpp" />
|
||||
<ClCompile Include="Logging.cpp" />
|
||||
<ClCompile Include="OpenVR-SpaceCalibratorDriver.cpp" />
|
||||
<ClCompile Include="ServerTrackedDeviceProvider.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="OpenVR-SpaceCalibratorDriver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Logging.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ServerTrackedDeviceProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VRWatchdogProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPCServer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Protocol.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Hooking.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InterfaceHookInjector.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="OpenVR-SpaceCalibratorDriver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Logging.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ServerTrackedDeviceProvider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPCServer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Hooking.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InterfaceHookInjector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
#include "Logging.h"
|
||||
#include "InterfaceHookInjector.h"
|
||||
|
||||
vr::EVRInitError ServerTrackedDeviceProvider::Init(vr::IVRDriverContext *pDriverContext)
|
||||
{
|
||||
TRACE("ServerTrackedDeviceProvider::Init()");
|
||||
VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext);
|
||||
|
||||
memset(transforms, 0, vr::k_unMaxTrackedDeviceCount * sizeof DeviceTransform);
|
||||
|
||||
InjectHooks(this, pDriverContext);
|
||||
server.Run();
|
||||
|
||||
return vr::VRInitError_None;
|
||||
}
|
||||
|
||||
void ServerTrackedDeviceProvider::Cleanup()
|
||||
{
|
||||
TRACE("ServerTrackedDeviceProvider::Cleanup()");
|
||||
server.Stop();
|
||||
DisableHooks();
|
||||
VR_CLEANUP_SERVER_DRIVER_CONTEXT();
|
||||
}
|
||||
|
||||
inline vr::HmdQuaternion_t operator*(const vr::HmdQuaternion_t &lhs, const vr::HmdQuaternion_t &rhs) {
|
||||
return {
|
||||
(lhs.w * rhs.w) - (lhs.x * rhs.x) - (lhs.y * rhs.y) - (lhs.z * rhs.z),
|
||||
(lhs.w * rhs.x) + (lhs.x * rhs.w) + (lhs.y * rhs.z) - (lhs.z * rhs.y),
|
||||
(lhs.w * rhs.y) + (lhs.y * rhs.w) + (lhs.z * rhs.x) - (lhs.x * rhs.z),
|
||||
(lhs.w * rhs.z) + (lhs.z * rhs.w) + (lhs.x * rhs.y) - (lhs.y * rhs.x)
|
||||
};
|
||||
}
|
||||
|
||||
inline vr::HmdVector3d_t quaternionRotateVector(const vr::HmdQuaternion_t& quat, const double(&vector)[3]) {
|
||||
vr::HmdQuaternion_t vectorQuat = { 0.0, vector[0], vector[1] , vector[2] };
|
||||
vr::HmdQuaternion_t conjugate = { quat.w, -quat.x, -quat.y, -quat.z };
|
||||
auto rotatedVectorQuat = quat * vectorQuat * conjugate;
|
||||
return { rotatedVectorQuat.x, rotatedVectorQuat.y, rotatedVectorQuat.z };
|
||||
}
|
||||
|
||||
void ServerTrackedDeviceProvider::SetDeviceTransform(const protocol::SetDeviceTransform &newTransform)
|
||||
{
|
||||
auto &tf = transforms[newTransform.openVRID];
|
||||
tf.enabled = newTransform.enabled;
|
||||
|
||||
if (newTransform.updateTranslation)
|
||||
tf.translation = newTransform.translation;
|
||||
|
||||
if (newTransform.updateRotation)
|
||||
tf.rotation = newTransform.rotation;
|
||||
}
|
||||
|
||||
bool ServerTrackedDeviceProvider::HandleDevicePoseUpdated(uint32_t openVRID, vr::DriverPose_t &pose)
|
||||
{
|
||||
auto &tf = transforms[openVRID];
|
||||
if (tf.enabled)
|
||||
{
|
||||
pose.qWorldFromDriverRotation = tf.rotation * pose.qWorldFromDriverRotation;
|
||||
|
||||
vr::HmdVector3d_t rotatedTranslation = quaternionRotateVector(tf.rotation, pose.vecWorldFromDriverTranslation);
|
||||
pose.vecWorldFromDriverTranslation[0] = rotatedTranslation.v[0] + tf.translation.v[0];
|
||||
pose.vecWorldFromDriverTranslation[1] = rotatedTranslation.v[1] + tf.translation.v[1];
|
||||
pose.vecWorldFromDriverTranslation[2] = rotatedTranslation.v[2] + tf.translation.v[2];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "IPCServer.h"
|
||||
|
||||
#include <openvr_driver.h>
|
||||
|
||||
class ServerTrackedDeviceProvider : public vr::IServerTrackedDeviceProvider
|
||||
{
|
||||
public:
|
||||
////// Start vr::IServerTrackedDeviceProvider functions
|
||||
|
||||
/** initializes the driver. This will be called before any other methods are called. */
|
||||
virtual vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext) override;
|
||||
|
||||
/** cleans up the driver right before it is unloaded */
|
||||
virtual void Cleanup() override;
|
||||
|
||||
/** Returns the version of the ITrackedDeviceServerDriver interface used by this driver */
|
||||
virtual const char * const *GetInterfaceVersions() { return vr::k_InterfaceVersions; }
|
||||
|
||||
/** Allows the driver do to some work in the main loop of the server. */
|
||||
virtual void RunFrame() { }
|
||||
|
||||
/** Returns true if the driver wants to block Standby mode. */
|
||||
virtual bool ShouldBlockStandbyMode() { return false; }
|
||||
|
||||
/** Called when the system is entering Standby mode. The driver should switch itself into whatever sort of low-power
|
||||
* state it has. */
|
||||
virtual void EnterStandby() { }
|
||||
|
||||
/** Called when the system is leaving Standby mode. The driver should switch itself back to
|
||||
full operation. */
|
||||
virtual void LeaveStandby() { }
|
||||
|
||||
////// End vr::IServerTrackedDeviceProvider functions
|
||||
|
||||
ServerTrackedDeviceProvider() : server(this) { }
|
||||
void SetDeviceTransform(const protocol::SetDeviceTransform &newTransform);
|
||||
bool HandleDevicePoseUpdated(uint32_t openVRID, vr::DriverPose_t &pose);
|
||||
|
||||
private:
|
||||
IPCServer server;
|
||||
|
||||
struct DeviceTransform
|
||||
{
|
||||
bool enabled = false;
|
||||
vr::HmdVector3d_t translation;
|
||||
vr::HmdQuaternion_t rotation;
|
||||
};
|
||||
|
||||
DeviceTransform transforms[vr::k_unMaxTrackedDeviceCount];
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvr_driver.h>
|
||||
|
||||
class VRWatchdogProvider : public vr::IVRWatchdogProvider
|
||||
{
|
||||
/** initializes the driver in watchdog mode. */
|
||||
virtual vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext)
|
||||
{
|
||||
VR_INIT_WATCHDOG_DRIVER_CONTEXT(pDriverContext);
|
||||
return vr::VRInitError_None;
|
||||
}
|
||||
|
||||
/** cleans up the driver right before it is unloaded */
|
||||
virtual void Cleanup()
|
||||
{
|
||||
VR_CLEANUP_WATCHDOG_DRIVER_CONTEXT()
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "Logging.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <cstdio>
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
OpenLogFile();
|
||||
LOG("OpenVR-SpaceCalibratorDriver loaded");
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
LOG("OpenVR-SpaceCalibratorDriver unloaded");
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef _OPENVR_API
|
||||
#include <openvr_driver.h>
|
||||
#endif
|
||||
|
||||
#define OPENVR_SPACECALIBRATOR_PIPE_NAME "\\\\.\\pipe\\OpenVRSpaceCalibratorDriver"
|
||||
|
||||
namespace protocol
|
||||
{
|
||||
const uint32_t Version = 1;
|
||||
|
||||
enum RequestType
|
||||
{
|
||||
RequestInvalid,
|
||||
RequestHandshake,
|
||||
RequestSetDeviceTransform,
|
||||
};
|
||||
|
||||
enum ResponseType
|
||||
{
|
||||
ResponseInvalid,
|
||||
ResponseHandshake,
|
||||
ResponseSuccess,
|
||||
};
|
||||
|
||||
struct Protocol
|
||||
{
|
||||
uint32_t version = Version;
|
||||
};
|
||||
|
||||
struct SetDeviceTransform
|
||||
{
|
||||
uint32_t openVRID;
|
||||
bool enabled;
|
||||
bool updateTranslation;
|
||||
bool updateRotation;
|
||||
vr::HmdVector3d_t translation;
|
||||
vr::HmdQuaternion_t rotation;
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(false), updateRotation(false) { }
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled, vr::HmdVector3d_t translation) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(true), updateRotation(false), translation(translation) { }
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled, vr::HmdQuaternion_t rotation) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(false), updateRotation(true), rotation(rotation) { }
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled, vr::HmdVector3d_t translation, vr::HmdQuaternion_t rotation) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(true), updateRotation(true), translation(translation), rotation(rotation) { }
|
||||
};
|
||||
|
||||
struct Request
|
||||
{
|
||||
RequestType type;
|
||||
|
||||
union {
|
||||
SetDeviceTransform setDeviceTransform;
|
||||
};
|
||||
|
||||
Request() : type(RequestInvalid) { }
|
||||
Request(RequestType type) : type(type) { }
|
||||
};
|
||||
|
||||
struct Response
|
||||
{
|
||||
ResponseType type;
|
||||
|
||||
union {
|
||||
Protocol protocol;
|
||||
};
|
||||
|
||||
Response() : type(ResponseInvalid) { }
|
||||
Response(ResponseType type) : type(type) { }
|
||||
};
|
||||
}
|
||||
@@ -1,52 +1,47 @@
|
||||
# OpenVR-SpaceCalibrator
|
||||
# OpenVR Space Calibrator
|
||||
|
||||
Use VR devices from one company with any other.
|
||||
Use tracked VR devices from one company with any other.
|
||||
|
||||
This is **beta software** and may not work for you. A quick video walkthrough of the calibration process is available at https://www.youtube.com/watch?v=W3TnQd9JMl4
|
||||
This is **experimental software** and may not work for your setup. It's well-tested for the Rift with Vive trackers though, with a community of a few hundred users ([Discord][]). It also seems to work for various HMDs (Windows MR, Rift) with Vive controllers and Knuckles prototypes. A quick video of how this works using an old version (~v0.3) is available at https://www.youtube.com/watch?v=W3TnQd9JMl4.
|
||||
|
||||
## Usage
|
||||
[Discord]: https://discord.gg/m7g2Wyj
|
||||
|
||||
### Install
|
||||
|
||||
Before following the directions below, download and run the installer for the [latest release](https://github.com/pushrax/OpenVR-SpaceCalibrator/releases). This will automatically set up SteamVR for use with multiple tracking systems (`activateMultipleDrivers: true`).
|
||||
|
||||
### Usage
|
||||
|
||||
Once Space Calibrator has a calibration, it works in the background to keep your devices configured correctly. Since v0.8, everything aside from creating the calibration is automated.
|
||||
|
||||
### Calibration
|
||||
|
||||
If you don't already run a setup with multiple device types, see [Setting up SteamVR](#setting-up-steamvr).
|
||||
As part of first time setup, or when you make a change to your space (e.g. move a sensor), and occasionally as the calibration drifts over time (consumer VR tracking isn't perfectly stable), you'll need to run a calibration:
|
||||
|
||||
0. Install [OpenVR-InputEmulator](https://github.com/matzman666/OpenVR-InputEmulator).
|
||||
1. Download and unzip the [latest release](https://github.com/pushrax/OpenVR-SpaceCalibrator/releases) of OpenVR-SpaceCalibrator.
|
||||
2. Run SteamVR, and turn on your Touch controllers and only one Vive device to use for calibration.
|
||||
3. Run OpenVR-SpaceCalibrator.
|
||||
4. Hold the left Touch controller and your Vive device in your left hand securely, like they're glued together.
|
||||
5. Click "Start Calibration"
|
||||
6. Wave your left hand around, like you're calibrating the compass on your phone. You want to get as many orientations as possible.
|
||||
7. Done! A profile will be saved automatically. You can turn on the rest of your Vive devices now.
|
||||
1. Copy the chaperone/guardian bounds from your HMD's play space. This doesn't need to be run if your HMD's play space hasn't changed since last time you copied it. __Example:__ if you're using the Rift with Vive trackers and you bump a Vive lighthouse, or if the calibration has just drifted a little, you likely don't need to run this step, but if you bump an Oculus sensor you will (after running Oculus guardian setup again).
|
||||
1. Run SteamVR, with only devices from your HMD's tracking system powered on. __Example:__ for Rift with Vive trackers, don't turn on the trackers yet.
|
||||
2. Confirm your chaperone/guardian is set up with the walls in the right place. If you change it later, you need to run step again.
|
||||
3. Open SPACE CAL in the SteamVR dashboard overlay.
|
||||
4. Click `Copy Chaperone Bounds to profile`
|
||||
|
||||
Next time you run SteamVR and OpenVR-InputEmulator it will load the calibration automatically and apply it to any Vive devices you turn on.
|
||||
2. Calibrate devices.
|
||||
1. Open SteamVR if you haven't already. Turn on some or all your devices.
|
||||
2. Open SPACE CAL in the SteamVR dashboard overlay.
|
||||
3. Select one device from the reference space on the left and one device from the target space on the right. If you turned on multiple devices from one space and can't tell which one is selected, click "Identify selected devices" to blink an LED or vibrate it. __Example:__ for Rift with Vive trackers, you'll see the Touch controllers on the left, and Vive trackers on the right. __Pro tip:__ if you turn on just one Vive tracker, you don't have to figure out which one is selected.
|
||||
4. Hold these two devices in one hand, like they're glued together. If they slip, calibration won't work as well.
|
||||
5. Click `Start Calibration`
|
||||
6. Move and rotate your hand around slowly a few times, like you're calibrating the compass on your phone. You want to sample as many orientations as possible.
|
||||
7. Done! A profile will be saved automatically. If you haven't already, turn on all your devices. Space Calibrator will automatically apply the calibration to devices as they turn on.
|
||||
|
||||
### Setting up SteamVR
|
||||
### Calibration outside VR
|
||||
|
||||
Every hardware designer with their own tracking system needs to make a "driver"
|
||||
so SteamVR can see their tracking data. SteamVR by default will load only one driver at a time,
|
||||
but we can tell it to load all of them by editing the vrsettings config file.
|
||||
|
||||
Open `Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings` in a text editor,
|
||||
look for the line that has `"activateMultipleDrivers": false` and change the `false` to `true`.
|
||||
In some guides online you may also see references to `requireHmd`, this does _not_ need to be changed
|
||||
unless you truly want to be able to run without any kind of HMD.
|
||||
|
||||
Sometimes when SteamVR updates this file seems to get wiped, if your setup stops working you might
|
||||
have to edit the config again.
|
||||
|
||||
### Manually editing the calibration
|
||||
|
||||
If you'd like to make a manual change to the calibration, the values are in `openvr_space_calibration.txt` in the same folder as the exe.
|
||||
The first 3 numbers are the rotation (yaw, pitch, roll) in degrees, and the next 3 numbers are the translation (x, y, z) in centimeters.
|
||||
You can calibrate without using the dashboard overlay by unminimizing Space Calibrator after opening SteamVR (it starts minimized). This is required if you're calibrating for a lone HMD without any devices in its tracking system.
|
||||
|
||||
### Compiling your own build
|
||||
|
||||
1. Install boost 1.63 to `lib/boost_1_63_0` (required for IPC to OpenVR-InputEmulator). https://sourceforge.net/projects/boost/files/boost-binaries/1.63.0/
|
||||
2. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.
|
||||
Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build. There are no external dependencies.
|
||||
|
||||
|
||||
## The math
|
||||
### The math
|
||||
|
||||
See [math.pdf](https://github.com/pushrax/OpenVR-SpaceCalibrator/blob/master/math.pdf) for details.
|
||||
If you have some ideas for how to improve the calibration process, let me know!
|
||||
@@ -0,0 +1,192 @@
|
||||
;--------------------------------
|
||||
;Include Modern UI
|
||||
|
||||
!include "MUI2.nsh"
|
||||
|
||||
;--------------------------------
|
||||
;General
|
||||
|
||||
!define OVERLAY_BASEDIR "..\client_overlay\bin\win64"
|
||||
!define DRIVER_RESDIR "..\OpenVR-SpaceCalibratorDriver\01spacecalibrator"
|
||||
|
||||
Name "OpenVR-SpaceCalibrator"
|
||||
OutFile "OpenVR-SpaceCalibrator.exe"
|
||||
InstallDir "$PROGRAMFILES64\OpenVR-SpaceCalibrator"
|
||||
InstallDirRegKey HKLM "Software\OpenVR-SpaceCalibrator\Main" ""
|
||||
RequestExecutionLevel admin
|
||||
ShowInstDetails show
|
||||
|
||||
;--------------------------------
|
||||
;Variables
|
||||
|
||||
VAR upgradeInstallation
|
||||
|
||||
;--------------------------------
|
||||
;Interface Settings
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
|
||||
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE dirPre
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
;--------------------------------
|
||||
;Languages
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
;--------------------------------
|
||||
;Macros
|
||||
|
||||
;--------------------------------
|
||||
;Functions
|
||||
|
||||
Function dirPre
|
||||
StrCmp $upgradeInstallation "true" 0 +2
|
||||
Abort
|
||||
FunctionEnd
|
||||
|
||||
Function .onInit
|
||||
StrCpy $upgradeInstallation "false"
|
||||
|
||||
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator" "UninstallString"
|
||||
StrCmp $R0 "" done
|
||||
|
||||
|
||||
; If SteamVR is already running, display a warning message and exit
|
||||
FindWindow $0 "Qt5QWindowIcon" "SteamVR Status"
|
||||
StrCmp $0 0 +3
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION \
|
||||
"SteamVR is still running. Cannot install this software.$\nPlease close SteamVR and try again."
|
||||
Abort
|
||||
|
||||
|
||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||
"OpenVR-SpaceCalibrator is already installed. $\n$\nClick `OK` to upgrade the \
|
||||
existing installation or `Cancel` to cancel this upgrade." \
|
||||
IDOK upgrade
|
||||
Abort
|
||||
|
||||
upgrade:
|
||||
StrCpy $upgradeInstallation "true"
|
||||
done:
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Installer Sections
|
||||
|
||||
Section "Install" SecInstall
|
||||
|
||||
StrCmp $upgradeInstallation "true" 0 noupgrade
|
||||
DetailPrint "Uninstall previous version..."
|
||||
ExecWait '"$INSTDIR\Uninstall.exe" /S _?=$INSTDIR'
|
||||
Delete $INSTDIR\Uninstall.exe
|
||||
Goto afterupgrade
|
||||
|
||||
noupgrade:
|
||||
|
||||
afterupgrade:
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
File "..\LICENSE"
|
||||
File "..\x64\Release\OpenVR-SpaceCalibrator.exe"
|
||||
File "..\x64\Release\openvr_api.dll"
|
||||
File "..\OpenVR-SpaceCalibrator\manifest.vrmanifest"
|
||||
File "..\OpenVR-SpaceCalibrator\icon.png"
|
||||
|
||||
ExecWait '"$INSTDIR\vcredist_x64.exe" /install /quiet'
|
||||
|
||||
Var /GLOBAL vrRuntimePath
|
||||
nsExec::ExecToStack '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -openvrpath'
|
||||
Pop $0
|
||||
Pop $vrRuntimePath
|
||||
DetailPrint "VR runtime path: $vrRuntimePath"
|
||||
|
||||
; Old beta driver
|
||||
StrCmp $upgradeInstallation "true" 0 nocleanupbeta
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\driver.vrdrivermanifest"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\resources\driver.vrresources"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\resources\settings\default.vrsettings"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\bin\win64\driver_000spacecalibrator.dll"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\bin\win64\space_calibrator_driver.log"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\resources\settings"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\resources\"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\bin\win64\"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\bin\"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\"
|
||||
nocleanupbeta:
|
||||
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator"
|
||||
File "${DRIVER_RESDIR}\driver.vrdrivermanifest"
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator\resources"
|
||||
File "${DRIVER_RESDIR}\resources\driver.vrresources"
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator\resources\settings"
|
||||
File "${DRIVER_RESDIR}\resources\settings\default.vrsettings"
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator\bin\win64"
|
||||
File "..\x64\Release\driver_01spacecalibrator.dll"
|
||||
|
||||
WriteRegStr HKLM "Software\OpenVR-SpaceCalibrator\Main" "" $INSTDIR
|
||||
WriteRegStr HKLM "Software\OpenVR-SpaceCalibrator\Driver" "" $vrRuntimePath
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator" "DisplayName" "OpenVR-SpaceCalibrator"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
|
||||
|
||||
CreateShortCut "$SMPROGRAMS\OpenVR-SpaceCalibrator.lnk" "$INSTDIR\OpenVR-SpaceCalibrator.exe"
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
nsExec::ExecToLog '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -installmanifest'
|
||||
nsExec::ExecToLog '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -activatemultipledrivers'
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Uninstaller Section
|
||||
|
||||
Section "Uninstall"
|
||||
; If SteamVR is already running, display a warning message and exit
|
||||
FindWindow $0 "Qt5QWindowIcon" "SteamVR Status"
|
||||
StrCmp $0 0 +3
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION \
|
||||
"SteamVR is still running. Cannot uninstall this software.$\nPlease close SteamVR and try again."
|
||||
Abort
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
nsExec::ExecToLog '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -removemanifest'
|
||||
|
||||
Var /GLOBAL vrRuntimePath2
|
||||
ReadRegStr $vrRuntimePath2 HKLM "Software\OpenVR-SpaceCalibrator\Driver" ""
|
||||
DetailPrint "VR runtime path: $vrRuntimePath2"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\driver.vrdrivermanifest"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\resources\driver.vrresources"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\resources\settings\default.vrsettings"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\bin\win64\driver_01spacecalibrator.dll"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\bin\win64\space_calibrator_driver.log"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\resources\settings"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\resources\"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\bin\win64\"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\bin\"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\"
|
||||
|
||||
Delete "$INSTDIR\LICENSE"
|
||||
Delete "$INSTDIR\OpenVR-SpaceCalibrator.exe"
|
||||
Delete "$INSTDIR\openvr_api.dll"
|
||||
Delete "$INSTDIR\manifest.vrmanifest"
|
||||
Delete "$INSTDIR\icon.png"
|
||||
|
||||
DeleteRegKey HKLM "Software\OpenVR-SpaceCalibrator\Main"
|
||||
DeleteRegKey HKLM "Software\OpenVR-SpaceCalibrator\Driver"
|
||||
DeleteRegKey HKLM "Software\OpenVR-SpaceCalibrator"
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator"
|
||||
|
||||
Delete "$SMPROGRAMS\OpenVR-SpaceCalibrator.lnk"
|
||||
SectionEnd
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
================================================================================
|
||||
Hacker Disassembler Engine 32 C
|
||||
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Hacker Disassembler Engine 64 C
|
||||
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a Hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
// ppTarget [out] A pointer to the target function, which will be used
|
||||
// with other functions.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2830,6 +2830,26 @@ void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data
|
||||
GImAllocatorUserData = user_data;
|
||||
}
|
||||
|
||||
int ImGui::GetActiveText(char *buf, int buf_size)
|
||||
{
|
||||
auto text = GImGui->InputTextState.Text;
|
||||
return ImTextStrToUtf8(buf, buf_size, text.Data, text.Data + text.Size);
|
||||
}
|
||||
|
||||
void ImGui::SetActiveText(const char *buf, int buf_size)
|
||||
{
|
||||
auto &edit_state = GImGui->InputTextState;
|
||||
auto &text = edit_state.Text;
|
||||
|
||||
if (text.Size < buf_size)
|
||||
buf_size = text.Size;
|
||||
|
||||
const char* buf_end = NULL;
|
||||
edit_state.CurLenW = ImTextStrFromUtf8(text.Data, buf_size, buf, buf + buf_size, &buf_end);
|
||||
edit_state.CurLenA = (int)(buf_end - buf);
|
||||
edit_state.CursorClamp();
|
||||
}
|
||||
|
||||
ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
|
||||
{
|
||||
ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
|
||||
|
||||
@@ -148,6 +148,10 @@ struct ImVec4
|
||||
// (In a namespace so you can add extra functions in your own separate file. Please don't modify imgui.cpp/.h!)
|
||||
namespace ImGui
|
||||
{
|
||||
IMGUI_API int GetActiveText(char *buf, int buf_size);
|
||||
IMGUI_API void SetActiveText(const char *buf, int buf_size);
|
||||
IMGUI_API void ClearActiveID();
|
||||
|
||||
// Context creation and access
|
||||
// Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts.
|
||||
// All those functions are not reliant on the current context.
|
||||
|
||||
@@ -54,6 +54,7 @@ static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
|
||||
static double g_Time = 0.0;
|
||||
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
|
||||
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
|
||||
static bool g_EnableMouseInput = true;
|
||||
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
@@ -108,6 +109,11 @@ void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
||||
glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_SetReadMouseFromGlfw(bool enabled)
|
||||
{
|
||||
g_EnableMouseInput = enabled;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||
{
|
||||
g_Window = window;
|
||||
@@ -185,6 +191,9 @@ void ImGui_ImplGlfw_Shutdown()
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||
{
|
||||
if (!g_EnableMouseInput)
|
||||
return;
|
||||
|
||||
// Update buttons
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
@@ -194,22 +203,22 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||
g_MouseJustPressed[i] = false;
|
||||
}
|
||||
|
||||
if (!glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
|
||||
return;
|
||||
|
||||
// Update mouse position
|
||||
const ImVec2 mouse_pos_backup = io.MousePos;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
|
||||
{
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
@@ -238,6 +247,7 @@ void ImGui_ImplGlfw_NewFrame()
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame()
|
||||
|
||||
#if false // Rendering to our own framebuffer
|
||||
// Setup display size
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
@@ -245,6 +255,7 @@ void ImGui_ImplGlfw_NewFrame()
|
||||
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
|
||||
#endif
|
||||
|
||||
// Setup time step
|
||||
double current_time = glfwGetTime();
|
||||
|
||||
@@ -30,3 +30,5 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, i
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_SetReadMouseFromGlfw(bool enabled);
|
||||
@@ -259,7 +259,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"out vec4 Out_Color;\n"
|
||||
"layout(location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
|
||||
|
||||
@@ -1,484 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "vrinputemulator_types.h"
|
||||
#include <utility>
|
||||
|
||||
|
||||
#define IPC_PROTOCOL_VERSION 3
|
||||
|
||||
namespace vrinputemulator {
|
||||
namespace ipc {
|
||||
|
||||
|
||||
enum class RequestType : uint32_t {
|
||||
None,
|
||||
|
||||
// IPC connection handling
|
||||
IPC_ClientConnect,
|
||||
IPC_ClientDisconnect,
|
||||
IPC_Ping,
|
||||
|
||||
// These are indented to inject events into OpenVR and require an OpenVR device id.
|
||||
// These are "fire and forget".
|
||||
OpenVR_PoseUpdate,
|
||||
OpenVR_ButtonEvent,
|
||||
OpenVR_AxisEvent,
|
||||
OpenVR_ProximitySensorEvent,
|
||||
OpenVR_VendorSpecificEvent,
|
||||
|
||||
// These are indented to manage virtual devices and require the internal device id.
|
||||
// The Reply is send to the client's message queue.
|
||||
VirtualDevices_AddDevice,
|
||||
VirtualDevices_PublishDevice,
|
||||
VirtualDevices_GetDeviceCount,
|
||||
VirtualDevices_GetDeviceInfo,
|
||||
VirtualDevices_GetDevicePose,
|
||||
VirtualDevices_GetControllerState,
|
||||
VirtualDevices_SetDeviceProperty,
|
||||
VirtualDevices_RemoveDeviceProperty,
|
||||
VirtualDevices_SetDevicePose,
|
||||
VirtualDevices_SetControllerState,
|
||||
|
||||
DeviceManipulation_GetDeviceInfo,
|
||||
DeviceManipulation_ButtonMapping,
|
||||
DeviceManipulation_GetDeviceOffsets,
|
||||
DeviceManipulation_SetDeviceOffsets,
|
||||
DeviceManipulation_DefaultMode,
|
||||
DeviceManipulation_RedirectMode,
|
||||
DeviceManipulation_SwapMode,
|
||||
DeviceManipulation_MotionCompensationMode,
|
||||
DeviceManipulation_FakeDisconnectedMode,
|
||||
DeviceManipulation_TriggerHapticPulse,
|
||||
DeviceManipulation_SetMotionCompensationProperties,
|
||||
|
||||
InputRemapping_SetDigitalRemapping,
|
||||
InputRemapping_GetDigitalRemapping,
|
||||
InputRemapping_SetAnalogRemapping,
|
||||
InputRemapping_GetAnalogRemapping,
|
||||
InputRemapping_SetTouchpadEmulationFixEnabled
|
||||
};
|
||||
|
||||
|
||||
enum class ReplyType : uint32_t {
|
||||
None,
|
||||
|
||||
IPC_ClientConnect,
|
||||
IPC_Ping,
|
||||
|
||||
GenericReply,
|
||||
|
||||
VirtualDevices_GetDeviceCount,
|
||||
VirtualDevices_GetDeviceInfo,
|
||||
VirtualDevices_GetDevicePose,
|
||||
VirtualDevices_GetControllerState,
|
||||
VirtualDevices_AddDevice,
|
||||
|
||||
DeviceManipulation_GetDeviceInfo,
|
||||
DeviceManipulation_GetDeviceOffsets,
|
||||
|
||||
InputRemapping_GetDigitalRemapping,
|
||||
InputRemapping_GetAnalogRemapping
|
||||
};
|
||||
|
||||
|
||||
enum class ReplyStatus : uint32_t {
|
||||
None,
|
||||
Ok,
|
||||
UnknownError,
|
||||
InvalidId,
|
||||
AlreadyInUse,
|
||||
InvalidType,
|
||||
NotFound,
|
||||
TooManyDevices,
|
||||
InvalidVersion,
|
||||
MissingProperty,
|
||||
InvalidOperation,
|
||||
NotTracking
|
||||
};
|
||||
|
||||
|
||||
struct Request_IPC_ClientConnect {
|
||||
uint32_t messageId;
|
||||
uint32_t ipcProcotolVersion;
|
||||
char queueName[128];
|
||||
};
|
||||
|
||||
|
||||
struct Request_IPC_ClientDisconnect {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId;
|
||||
};
|
||||
|
||||
|
||||
struct Request_IPC_Ping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId;
|
||||
uint64_t nonce;
|
||||
};
|
||||
|
||||
|
||||
struct Request_OpenVR_PoseUpdate {
|
||||
uint32_t deviceId;
|
||||
vr::DriverPose_t pose;
|
||||
};
|
||||
|
||||
|
||||
#define REQUEST_OPENVR_BUTTONEVENT_MAXCOUNT 12
|
||||
|
||||
struct Request_OpenVR_ButtonEvent {
|
||||
unsigned eventCount;
|
||||
struct {
|
||||
ButtonEventType eventType;
|
||||
uint32_t deviceId;
|
||||
vr::EVRButtonId buttonId;
|
||||
double timeOffset;
|
||||
} events[REQUEST_OPENVR_BUTTONEVENT_MAXCOUNT];
|
||||
};
|
||||
|
||||
|
||||
#define REQUEST_OPENVR_AXISEVENT_MAXCOUNT 12
|
||||
|
||||
struct Request_OpenVR_AxisEvent {
|
||||
unsigned eventCount;
|
||||
struct {
|
||||
uint32_t deviceId;
|
||||
uint32_t axisId;
|
||||
vr::VRControllerAxis_t axisState;
|
||||
} events[REQUEST_OPENVR_AXISEVENT_MAXCOUNT];
|
||||
};
|
||||
|
||||
|
||||
struct Request_OpenVR_ProximitySensorEvent {
|
||||
uint32_t deviceId;
|
||||
bool sensorTriggered;
|
||||
};
|
||||
|
||||
|
||||
struct Request_OpenVR_VendorSpecificEvent {
|
||||
uint32_t deviceId;
|
||||
vr::EVREventType eventType;
|
||||
vr::VREvent_Data_t eventData;
|
||||
double timeOffset;
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_GenericClientMessage {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_GenericDeviceIdMessage {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_AddDevice {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
VirtualDeviceType deviceType;
|
||||
char deviceSerial[256];
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_SetDeviceProperty {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::ETrackedDeviceProperty deviceProperty;
|
||||
DevicePropertyValueType valueType;
|
||||
union {
|
||||
int32_t int32Value;
|
||||
uint64_t uint64Value;
|
||||
float floatValue;
|
||||
bool boolValue;
|
||||
char stringValue[256];
|
||||
vr::HmdMatrix34_t matrix34Value;
|
||||
vr::HmdMatrix44_t matrix44Value;
|
||||
vr::HmdVector3_t vector3Value;
|
||||
vr::HmdVector4_t vector4Value;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct Request_VirtualDevices_RemoveDeviceProperty {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::ETrackedDeviceProperty deviceProperty;
|
||||
};
|
||||
|
||||
struct Request_VirtualDevices_SetDevicePose {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::DriverPose_t pose;
|
||||
};
|
||||
|
||||
struct Request_VirtualDevices_SetControllerState {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::VRControllerState_t controllerState;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_ButtonMapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t enableMapping; // 0 .. don't change, 1 .. enable, 2 .. disable
|
||||
uint32_t mappingOperation; // 0 .. do nothing, 1 .. add given mappings, 2 .. remove given mappings, 3 .. remove all mappings
|
||||
uint32_t mappingCount;
|
||||
vr::EVRButtonId buttonMappings[32];
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_SetDeviceOffsets {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t enableOffsets; // 0 .. don't change, 1 .. enable, 2 .. disable
|
||||
uint32_t offsetOperation; // 0 .. set, 1 .. add
|
||||
// world-from-driver universe offsets
|
||||
bool worldFromDriverRotationOffsetValid;
|
||||
vr::HmdQuaternion_t worldFromDriverRotationOffset;
|
||||
bool worldFromDriverTranslationOffsetValid;
|
||||
vr::HmdVector3d_t worldFromDriverTranslationOffset;
|
||||
// driver-from-head universe offsets
|
||||
bool driverFromHeadRotationOffsetValid;
|
||||
vr::HmdQuaternion_t driverFromHeadRotationOffset;
|
||||
bool driverFromHeadTranslationOffsetValid;
|
||||
vr::HmdVector3d_t driverFromHeadTranslationOffset;
|
||||
// device offsets
|
||||
bool deviceRotationOffsetValid;
|
||||
vr::HmdQuaternion_t deviceRotationOffset;
|
||||
bool deviceTranslationOffsetValid;
|
||||
vr::HmdVector3d_t deviceTranslationOffset;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_RedirectMode {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t targetId;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_SwapMode {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t targetId;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_MotionCompensationMode {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
MotionCompensationVelAccMode velAccCompensationMode;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_TriggerHapticPulse {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t axisId;
|
||||
uint16_t durationMicroseconds;
|
||||
bool directMode;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_SetMotionCompensationProperties {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
bool velAccCompensationModeValid;
|
||||
MotionCompensationVelAccMode velAccCompensationMode;
|
||||
bool kalmanFilterProcessNoiseValid;
|
||||
double kalmanFilterProcessNoise;
|
||||
bool kalmanFilterObservationNoiseValid;
|
||||
double kalmanFilterObservationNoise;
|
||||
bool movingAverageWindowValid;
|
||||
unsigned movingAverageWindow;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_SetDigitalRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t buttonId;
|
||||
DigitalInputRemapping remapData;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_GetDigitalRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t buttonId;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_SetAnalogRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t axisId;
|
||||
AnalogInputRemapping remapData;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_GetAnalogRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t axisId;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_SetTouchpadEmulationFixEnabled {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
bool enable;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Request {
|
||||
Request() {}
|
||||
Request(RequestType type) : type(type) {
|
||||
timestamp = std::chrono::duration_cast <std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
Request(RequestType type, uint64_t timestamp) : type(type), timestamp(timestamp) {}
|
||||
|
||||
void refreshTimestamp() {
|
||||
timestamp = std::chrono::duration_cast <std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
RequestType type = RequestType::None;
|
||||
int64_t timestamp = 0; // milliseconds since epoch
|
||||
union MsgUnion {
|
||||
Request_IPC_ClientConnect ipc_ClientConnect;
|
||||
Request_IPC_ClientDisconnect ipc_ClientDisconnect;
|
||||
Request_IPC_Ping ipc_Ping;
|
||||
Request_OpenVR_PoseUpdate ipc_PoseUpdate;
|
||||
Request_OpenVR_ButtonEvent ipc_ButtonEvent;
|
||||
Request_OpenVR_AxisEvent ipc_AxisEvent;
|
||||
Request_OpenVR_ProximitySensorEvent ovr_ProximitySensorEvent;
|
||||
Request_OpenVR_VendorSpecificEvent ovr_VendorSpecificEvent;
|
||||
Request_VirtualDevices_GenericClientMessage vd_GenericClientMessage;
|
||||
Request_VirtualDevices_GenericDeviceIdMessage vd_GenericDeviceIdMessage;
|
||||
Request_VirtualDevices_AddDevice vd_AddDevice;
|
||||
Request_VirtualDevices_SetDeviceProperty vd_SetDeviceProperty;
|
||||
Request_VirtualDevices_RemoveDeviceProperty vd_RemoveDeviceProperty;
|
||||
Request_VirtualDevices_SetDevicePose vd_SetDevicePose;
|
||||
Request_VirtualDevices_SetControllerState vd_SetControllerState;
|
||||
Request_DeviceManipulation_ButtonMapping dm_ButtonMapping;
|
||||
Request_DeviceManipulation_SetDeviceOffsets dm_DeviceOffsets;
|
||||
Request_DeviceManipulation_RedirectMode dm_RedirectMode;
|
||||
Request_DeviceManipulation_SwapMode dm_SwapMode;
|
||||
Request_DeviceManipulation_MotionCompensationMode dm_MotionCompensationMode;
|
||||
Request_DeviceManipulation_TriggerHapticPulse dm_triggerHapticPulse;
|
||||
Request_DeviceManipulation_SetMotionCompensationProperties dm_SetMotionCompensationProperties;
|
||||
Request_InputRemapping_SetDigitalRemapping ir_SetDigitalRemapping;
|
||||
Request_InputRemapping_GetDigitalRemapping ir_GetDigitalRemapping;
|
||||
Request_InputRemapping_SetAnalogRemapping ir_SetAnalogRemapping;
|
||||
Request_InputRemapping_GetAnalogRemapping ir_GetAnalogRemapping;
|
||||
Request_InputRemapping_SetTouchpadEmulationFixEnabled ir_SetTouchPadEmulationFixEnabled;
|
||||
MsgUnion() {}
|
||||
} msg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Reply_IPC_ClientConnect {
|
||||
uint32_t clientId;
|
||||
uint32_t ipcProcotolVersion;
|
||||
};
|
||||
|
||||
struct Reply_IPC_Ping {
|
||||
uint64_t nonce;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetDeviceCount {
|
||||
uint32_t deviceCount;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetDeviceInfo {
|
||||
uint32_t virtualDeviceId;
|
||||
uint32_t openvrDeviceId;
|
||||
VirtualDeviceType deviceType;
|
||||
char deviceSerial[128];
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetDevicePose {
|
||||
vr::DriverPose_t pose;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetControllerState {
|
||||
vr::VRControllerState_t controllerState;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_AddDevice {
|
||||
uint32_t virtualDeviceId;
|
||||
};
|
||||
|
||||
|
||||
struct Reply_DeviceManipulation_GetDeviceInfo {
|
||||
uint32_t deviceId;
|
||||
vr::ETrackedDeviceClass deviceClass;
|
||||
int deviceMode;
|
||||
uint32_t refDeviceId;
|
||||
bool offsetsEnabled;
|
||||
bool redirectSuspended;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Reply_DeviceManipulation_GetDeviceOffsets {
|
||||
uint32_t deviceId;
|
||||
bool offsetsEnabled;
|
||||
vr::HmdQuaternion_t worldFromDriverRotationOffset;
|
||||
vr::HmdVector3d_t worldFromDriverTranslationOffset;
|
||||
vr::HmdQuaternion_t driverFromHeadRotationOffset;
|
||||
vr::HmdVector3d_t driverFromHeadTranslationOffset;
|
||||
vr::HmdQuaternion_t deviceRotationOffset;
|
||||
vr::HmdVector3d_t deviceTranslationOffset;
|
||||
};
|
||||
|
||||
struct Reply_InputRemapping_GetDigitalRemapping {
|
||||
uint32_t deviceId;
|
||||
uint32_t buttonId;
|
||||
DigitalInputRemapping remapData;
|
||||
};
|
||||
|
||||
struct Reply_InputRemapping_GetAnalogRemapping {
|
||||
uint32_t deviceId;
|
||||
uint32_t axisId;
|
||||
AnalogInputRemapping remapData;
|
||||
};
|
||||
|
||||
|
||||
struct Reply {
|
||||
Reply() {}
|
||||
Reply(ReplyType type) : type(type) {
|
||||
timestamp = std::chrono::duration_cast <std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
Reply(ReplyType type, uint64_t timestamp) : type(type), timestamp(timestamp) {}
|
||||
|
||||
ReplyType type = ReplyType::None;
|
||||
uint64_t timestamp = 0; // milliseconds since epoch
|
||||
uint32_t messageId;
|
||||
ReplyStatus status;
|
||||
union MsgUnion {
|
||||
Reply_IPC_ClientConnect ipc_ClientConnect;
|
||||
Reply_IPC_Ping ipc_Ping;
|
||||
Reply_VirtualDevices_GetDeviceCount vd_GetDeviceCount;
|
||||
Reply_VirtualDevices_GetDeviceInfo vd_GetDeviceInfo;
|
||||
Reply_VirtualDevices_GetDevicePose vd_GetDevicePose;
|
||||
Reply_VirtualDevices_GetControllerState vd_GetControllerState;
|
||||
Reply_VirtualDevices_AddDevice vd_AddDevice;
|
||||
Reply_DeviceManipulation_GetDeviceInfo dm_deviceInfo;
|
||||
Reply_DeviceManipulation_GetDeviceOffsets dm_deviceOffsets;
|
||||
Reply_InputRemapping_GetDigitalRemapping ir_getDigitalRemapping;
|
||||
Reply_InputRemapping_GetAnalogRemapping ir_getAnalogRemapping;
|
||||
MsgUnion() {}
|
||||
} msg;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace ipc
|
||||
} // end namespace vrinputemulator
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,229 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <openvr.h>
|
||||
#include <boost/interprocess/ipc/message_queue.hpp>
|
||||
|
||||
|
||||
namespace vr {
|
||||
// Copied from openvr_driver.h
|
||||
struct DriverPose_t {
|
||||
/* Time offset of this pose, in seconds from the actual time of the pose,
|
||||
* relative to the time of the PoseUpdated() call made by the driver.
|
||||
*/
|
||||
double poseTimeOffset;
|
||||
|
||||
/* Generally, the pose maintained by a driver
|
||||
* is in an inertial coordinate system different
|
||||
* from the world system of x+ right, y+ up, z+ back.
|
||||
* Also, the driver is not usually tracking the "head" position,
|
||||
* but instead an internal IMU or another reference point in the HMD.
|
||||
* The following two transforms transform positions and orientations
|
||||
* to app world space from driver world space,
|
||||
* and to HMD head space from driver local body space.
|
||||
*
|
||||
* We maintain the driver pose state in its internal coordinate system,
|
||||
* so we can do the pose prediction math without having to
|
||||
* use angular acceleration. A driver's angular acceleration is generally not measured,
|
||||
* and is instead calculated from successive samples of angular velocity.
|
||||
* This leads to a noisy angular acceleration values, which are also
|
||||
* lagged due to the filtering required to reduce noise to an acceptable level.
|
||||
*/
|
||||
vr::HmdQuaternion_t qWorldFromDriverRotation;
|
||||
double vecWorldFromDriverTranslation[3];
|
||||
|
||||
vr::HmdQuaternion_t qDriverFromHeadRotation;
|
||||
double vecDriverFromHeadTranslation[3];
|
||||
|
||||
/* State of driver pose, in meters and radians. */
|
||||
/* Position of the driver tracking reference in driver world space
|
||||
* +[0] (x) is right
|
||||
* +[1] (y) is up
|
||||
* -[2] (z) is forward
|
||||
*/
|
||||
double vecPosition[3];
|
||||
|
||||
/* Velocity of the pose in meters/second */
|
||||
double vecVelocity[3];
|
||||
|
||||
/* Acceleration of the pose in meters/second */
|
||||
double vecAcceleration[3];
|
||||
|
||||
/* Orientation of the tracker, represented as a quaternion */
|
||||
vr::HmdQuaternion_t qRotation;
|
||||
|
||||
/* Angular velocity of the pose in axis-angle
|
||||
* representation. The direction is the angle of
|
||||
* rotation and the magnitude is the angle around
|
||||
* that axis in radians/second. */
|
||||
double vecAngularVelocity[3];
|
||||
|
||||
/* Angular acceleration of the pose in axis-angle
|
||||
* representation. The direction is the angle of
|
||||
* rotation and the magnitude is the angle around
|
||||
* that axis in radians/second^2. */
|
||||
double vecAngularAcceleration[3];
|
||||
|
||||
ETrackingResult result;
|
||||
|
||||
bool poseIsValid;
|
||||
bool willDriftInYaw;
|
||||
bool shouldApplyHeadModel;
|
||||
bool deviceIsConnected;
|
||||
};
|
||||
} // end namespace vr
|
||||
|
||||
|
||||
#include "ipc_protocol.h"
|
||||
|
||||
|
||||
namespace vrinputemulator {
|
||||
|
||||
class vrinputemulator_exception : public std::runtime_error {
|
||||
public:
|
||||
const int errorcode = 0;
|
||||
using std::runtime_error::runtime_error;
|
||||
vrinputemulator_exception(const std::string& msg, int code) : std::runtime_error(msg), errorcode(code) {}
|
||||
};
|
||||
|
||||
class vrinputemulator_connectionerror : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_invalidversion : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_invalidid : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_invalidtype : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_notfound : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_alreadyinuse : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_toomanydevices : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
|
||||
struct VirtualDeviceInfo {
|
||||
uint32_t virtualDeviceId;
|
||||
uint32_t openvrDeviceId;
|
||||
VirtualDeviceType deviceType;
|
||||
std::string deviceSerial;
|
||||
};
|
||||
|
||||
|
||||
class VRInputEmulator {
|
||||
public:
|
||||
VRInputEmulator(const std::string& driverQueue = "driver_vrinputemulator.server_queue", const std::string& clientQueue = "driver_vrinputemulator.client_queue.");
|
||||
~VRInputEmulator();
|
||||
|
||||
void connect();
|
||||
bool isConnected() const;
|
||||
void disconnect();
|
||||
|
||||
void ping(bool modal = true, bool enableReply = false);
|
||||
|
||||
void openvrUpdatePose(uint32_t deviceId, const vr::DriverPose_t& pose);
|
||||
void openvrButtonEvent(ButtonEventType eventType, uint32_t deviceId, vr::EVRButtonId buttonId, double timeOffset = 0.0);
|
||||
void openvrAxisEvent(uint32_t deviceId, uint32_t axisId, const vr::VRControllerAxis_t& axisState);
|
||||
void openvrProximitySensorEvent(uint32_t deviceId, bool sensorTriggered);
|
||||
void openvrVendorSpecificEvent(uint32_t deviceId, vr::EVREventType eventType, const vr::VREvent_Data_t& eventData, double timeOffset = 0.0);
|
||||
|
||||
uint32_t getVirtualDeviceCount();
|
||||
VirtualDeviceInfo getVirtualDeviceInfo(uint32_t virtualDeviceId);
|
||||
vr::DriverPose_t getVirtualDevicePose(uint32_t virtualDeviceId);
|
||||
vr::VRControllerState_t getVirtualControllerState(uint32_t virtualDeviceId);
|
||||
uint32_t addVirtualDevice(VirtualDeviceType deviceType, const std::string& deviceSerial, bool softfail = true);
|
||||
void publishVirtualDevice(uint32_t virtualDeviceId, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, int32_t value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, uint64_t value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, float value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, bool value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, const std::string& value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, const char* value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, const vr::HmdMatrix34_t& value, bool modal = true);
|
||||
void removeVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, bool modal = true);
|
||||
void setVirtualDevicePose(uint32_t virtualDeviceId, const vr::DriverPose_t& pose, bool modal = true);
|
||||
void setVirtualControllerState(uint32_t virtualDeviceId, const vr::VRControllerState_t& state, bool modal = true);
|
||||
|
||||
void enableDeviceButtonMapping(uint32_t deviceId, bool enable, bool modal = true);
|
||||
void addDeviceButtonMapping(uint32_t deviceId, vr::EVRButtonId button, vr::EVRButtonId mapped, bool modal = true);
|
||||
void removeDeviceButtonMapping(uint32_t deviceId, vr::EVRButtonId button, bool modal = true);
|
||||
void removeAllDeviceButtonMappings(uint32_t deviceId, bool modal = true);
|
||||
|
||||
void getDeviceOffsets(uint32_t deviceId, DeviceOffsets& data);
|
||||
void enableDeviceOffsets(uint32_t deviceId, bool enable, bool modal = true);
|
||||
void setWorldFromDriverRotationOffset(uint32_t deviceId, const vr::HmdQuaternion_t& value, bool modal = true);
|
||||
void setWorldFromDriverTranslationOffset(uint32_t deviceId, const vr::HmdVector3d_t& value, bool modal = true);
|
||||
void setDriverFromHeadRotationOffset(uint32_t deviceId, const vr::HmdQuaternion_t& value, bool modal = true);
|
||||
void setDriverFromHeadTranslationOffset(uint32_t deviceId, const vr::HmdVector3d_t& value, bool modal = true);
|
||||
void setDriverRotationOffset(uint32_t deviceId, const vr::HmdQuaternion_t& value, bool modal = true);
|
||||
void setDriverTranslationOffset(uint32_t deviceId, const vr::HmdVector3d_t& value, bool modal = true);
|
||||
|
||||
void getDeviceInfo(uint32_t deviceId, DeviceInfo& info);
|
||||
void setDeviceNormalMode(uint32_t deviceId, bool modal = true);
|
||||
void setDeviceFakeDisconnectedMode(uint32_t deviceId, bool modal = true);
|
||||
void setDeviceRedictMode(uint32_t deviceId, uint32_t target, bool modal = true);
|
||||
void setDeviceSwapMode(uint32_t deviceId, uint32_t target, bool modal = true);
|
||||
void setDeviceMotionCompensationMode(uint32_t deviceId, MotionCompensationVelAccMode velAccMode = MotionCompensationVelAccMode::Disabled, bool modal = true);
|
||||
|
||||
void setMotionVelAccCompensationMode(MotionCompensationVelAccMode velAccMode, bool modal = true);
|
||||
void setMotionCompensationKalmanProcessNoise(double variance, bool modal = true);
|
||||
void setMotionCompensationKalmanObservationNoise(double variance, bool modal = true);
|
||||
void setMotionCompensationMovingAverageWindow(unsigned window, bool modal = true);
|
||||
|
||||
void triggerHapticPulse(uint32_t deviceId, uint32_t axisId, uint16_t durationMicroseconds, bool directMode, bool modal = true);
|
||||
|
||||
void setDigitalInputRemapping(uint32_t deviceId, uint32_t buttonId, const DigitalInputRemapping& remapping, bool modal = true);
|
||||
DigitalInputRemapping getDigitalInputRemapping(uint32_t deviceId, uint32_t buttonId);
|
||||
|
||||
void setAnalogInputRemapping(uint32_t deviceId, uint32_t axisId, const AnalogInputRemapping& remapping, bool modal = true);
|
||||
AnalogInputRemapping getAnalogInputRemapping(uint32_t deviceId, uint32_t axisId);
|
||||
|
||||
private:
|
||||
std::recursive_mutex _mutex;
|
||||
uint32_t m_clientId = 0;
|
||||
|
||||
bool _ipcThreadRunning = false;
|
||||
volatile bool _ipcThreadStop = false;
|
||||
std::thread _ipcThread;
|
||||
static void _ipcThreadFunc(VRInputEmulator* _this);
|
||||
|
||||
std::random_device _ipcRandomDevice;
|
||||
std::uniform_int_distribution<uint32_t> _ipcRandomDist;
|
||||
struct _ipcPromiseMapEntry {
|
||||
_ipcPromiseMapEntry() : isValid(false) {}
|
||||
_ipcPromiseMapEntry(std::promise<ipc::Reply>&& _promise, bool isValid = true)
|
||||
: promise(std::move(_promise)), isValid(isValid) {}
|
||||
bool isValid;
|
||||
std::promise<ipc::Reply> promise;
|
||||
};
|
||||
std::map<uint32_t, _ipcPromiseMapEntry> _ipcPromiseMap;
|
||||
std::string _ipcServerQueueName;
|
||||
std::string _ipcClientQueueName;
|
||||
boost::interprocess::message_queue* _ipcServerQueue = nullptr;
|
||||
boost::interprocess::message_queue* _ipcClientQueue = nullptr;
|
||||
|
||||
void _setVirtualDeviceProperty(uint32_t emulatorDeviceId, vr::ETrackedDeviceProperty deviceProperty, std::function<void(ipc::Request&)>, bool modal);
|
||||
};
|
||||
|
||||
} // end namespace vrinputemulator
|
||||
@@ -1,169 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace vrinputemulator {
|
||||
|
||||
static const char* const vrsettings_SectionName = "driver_00vrinputemulator";
|
||||
static const char* const vrsettings_overrideHmdManufacturer_string = "overrideHmdManufacturer";
|
||||
static const char* const vrsettings_overrideHmdModel_string = "overrideHmdModel";
|
||||
static const char* const vrsettings_overrideHmdTrackingSystem_string = "overrideHmdTrackingSystem";
|
||||
static const char* const vrsettings_genericTrackerFakeController_bool = "genericTrackerFakeController";
|
||||
|
||||
enum class VirtualDeviceType : uint32_t {
|
||||
None = 0,
|
||||
TrackedController = 1
|
||||
};
|
||||
|
||||
|
||||
enum class ButtonEventType : uint32_t {
|
||||
None = 0,
|
||||
ButtonPressed = 1,
|
||||
ButtonUnpressed = 2,
|
||||
ButtonTouched = 3,
|
||||
ButtonUntouched = 4,
|
||||
};
|
||||
|
||||
|
||||
enum class DevicePropertyValueType : uint32_t {
|
||||
None = 0,
|
||||
FLOAT = 1,
|
||||
INT32 = 2,
|
||||
UINT64 = 3,
|
||||
BOOL = 4,
|
||||
STRING = 5,
|
||||
MATRIX34 = 20,
|
||||
MATRIX44 = 21,
|
||||
VECTOR3 = 22,
|
||||
VECTOR4 = 23
|
||||
};
|
||||
|
||||
|
||||
struct DeviceOffsets {
|
||||
uint32_t deviceId;
|
||||
bool offsetsEnabled;
|
||||
vr::HmdQuaternion_t worldFromDriverRotationOffset;
|
||||
vr::HmdVector3d_t worldFromDriverTranslationOffset;
|
||||
vr::HmdQuaternion_t driverFromHeadRotationOffset;
|
||||
vr::HmdVector3d_t driverFromHeadTranslationOffset;
|
||||
vr::HmdQuaternion_t deviceRotationOffset;
|
||||
vr::HmdVector3d_t deviceTranslationOffset;
|
||||
};
|
||||
|
||||
|
||||
struct DeviceInfo {
|
||||
uint32_t deviceId;
|
||||
vr::ETrackedDeviceClass deviceClass;
|
||||
int deviceMode;
|
||||
uint32_t refDeviceId;
|
||||
bool offsetsEnabled;
|
||||
bool redirectSuspended;
|
||||
};
|
||||
|
||||
|
||||
enum class MotionCompensationVelAccMode : uint32_t {
|
||||
Disabled = 0,
|
||||
SetZero = 1,
|
||||
SubstractMotionRef = 2,
|
||||
LinearApproximation = 3,
|
||||
KalmanFilter = 4
|
||||
};
|
||||
|
||||
|
||||
enum class DigitalBindingType : uint32_t {
|
||||
NoRemapping = 0,
|
||||
Disabled = 1,
|
||||
OpenVR = 2,
|
||||
Keyboard = 3,
|
||||
SuspendRedirectMode = 4,
|
||||
ToggleTouchpadEmulationFix = 5
|
||||
};
|
||||
|
||||
|
||||
struct DigitalBinding {
|
||||
DigitalBindingType type = DigitalBindingType::NoRemapping;
|
||||
|
||||
union BindingUnion {
|
||||
struct {
|
||||
uint32_t controllerId;
|
||||
uint32_t buttonId;
|
||||
} openvr;
|
||||
|
||||
struct {
|
||||
bool shiftPressed = false;
|
||||
bool ctrlPressed = false;
|
||||
bool altPressed = false;
|
||||
uint32_t keyCode = 0x00;
|
||||
bool sendScanCode = true;
|
||||
} keyboard;
|
||||
|
||||
BindingUnion() {}
|
||||
} data;
|
||||
|
||||
bool toggleEnabled = false;
|
||||
uint32_t toggleDelay = 0;
|
||||
|
||||
bool autoTriggerEnabled = false;
|
||||
uint32_t autoTriggerFrequency = 1;
|
||||
|
||||
DigitalBinding() {}
|
||||
};
|
||||
|
||||
|
||||
struct DigitalInputRemapping {
|
||||
bool valid;
|
||||
DigitalBinding binding;
|
||||
|
||||
bool touchAsClick = false;
|
||||
|
||||
bool longPressEnabled = false;
|
||||
uint32_t longPressThreshold = 1000u;
|
||||
DigitalBinding longPressBinding;
|
||||
bool longPressImmediateRelease = false;
|
||||
|
||||
bool doublePressEnabled = false;
|
||||
uint32_t doublePressThreshold = 300;
|
||||
DigitalBinding doublePressBinding;
|
||||
bool doublePressImmediateRelease = false;
|
||||
|
||||
DigitalInputRemapping(bool valid = false) : valid(valid) {}
|
||||
};
|
||||
|
||||
|
||||
enum class AnalogBindingType : uint32_t {
|
||||
NoRemapping,
|
||||
Disabled,
|
||||
OpenVR
|
||||
};
|
||||
|
||||
struct AnalogBinding {
|
||||
AnalogBindingType type;
|
||||
union BindingUnion {
|
||||
struct {
|
||||
uint32_t controllerId = vr::k_unTrackedDeviceIndexInvalid;
|
||||
uint32_t axisId = 0;
|
||||
} openvr;
|
||||
BindingUnion() {}
|
||||
} data;
|
||||
bool invertXAxis = false;
|
||||
bool invertYAxis = false;
|
||||
bool swapAxes = false;
|
||||
float lowerDeadzone = 0.0;
|
||||
float upperDeadzone = 1.0;
|
||||
unsigned touchpadEmulationMode = 0; // 0 .. Disabled, 1 .. Position Based, 2 .. Position Based (Deferred Zero Updates)
|
||||
bool buttonPressDeadzoneFix = false;
|
||||
|
||||
AnalogBinding(AnalogBindingType type = AnalogBindingType::NoRemapping) : type(type) {}
|
||||
};
|
||||
|
||||
|
||||
struct AnalogInputRemapping {
|
||||
bool valid;
|
||||
AnalogBinding binding;
|
||||
|
||||
AnalogInputRemapping(bool valid = false) : valid(valid) {}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace vrinputemulator
|
||||
Binary file not shown.
Binary file not shown.
+1981
-351
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user