Compare commits

..
6 Commits
60 changed files with 4859 additions and 2925 deletions

No files matched your search

+1
View File
@@ -5,5 +5,6 @@ ipch
*.aps
*.user
/OpenVR-SpaceCalibrator/x64/
/OpenVR-SpaceCalibratorDriver/x64/
/x64/
/lib/boost*
+6
View File
@@ -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
+60 -62
View File
@@ -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,6 +260,19 @@ 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);
}
void ScanAndApplyProfile(CalibrationContext &ctx)
{
char buffer[vr::k_unMaxPropertyStringSize];
@@ -292,53 +288,52 @@ 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.validProfile)
{
ResetAndDisableOffsets(id);
continue;
}
if (deviceClass == vr::TrackedDeviceClass_TrackingReference || deviceClass == vr::TrackedDeviceClass_HMD)
{
//auto p = ctx.devicePoses[id].mDeviceToAbsoluteTracking.m;
//printf("REF %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
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)
{
ResetAndDisableOffsets(id);
continue;
if (deviceClass == vr::TrackedDeviceClass_TrackingReference || deviceClass == vr::TrackedDeviceClass_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]);
}
else
{
//printf("setting calibration for %d (%s)\n", id, buffer);
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
InputEmulator.setWorldFromDriverRotationOffset(id, vrRotQuat);
auto vrTransVec = VRTranslationVec(ctx.calibratedTranslation);
InputEmulator.setWorldFromDriverTranslationOffset(id, vrTransVec);
InputEmulator.enableDeviceOffsets(id, true);
}
protocol::Request req(protocol::RequestSetDeviceTransform);
req.setDeviceTransform = {
id,
true,
VRTranslationVec(ctx.calibratedTranslation),
VRRotationQuat(ctx.calibratedRotation)
};
Driver.SendBlocking(req);
}
}
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 +357,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 +367,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 +435,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,7 +447,10 @@ 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);
SaveProfile(ctx);
CalCtx.Message("Finished calibration, profile saved\n");
+2 -2
View File
@@ -15,7 +15,7 @@ enum class CalibrationState
struct CalibrationContext
{
CalibrationState state = CalibrationState::None;
int referenceID, targetID;
uint32_t referenceID, targetID;
Eigen::Vector3d calibratedRotation;
Eigen::Vector3d calibratedTranslation;
@@ -40,6 +40,6 @@ struct CalibrationContext
extern CalibrationContext CalCtx;
void InitVR();
void InitCalibrator();
void CalibrationTick(double time);
void StartCalibration();
+57 -2
View File
@@ -12,13 +12,28 @@
static void UpgradeProfileV1(CalibrationContext &ctx);
static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream);
static std::string ConfigFileName()
{
std::string vrRuntimeConfigName = vr::VR_RuntimePath();
return vrRuntimeConfigName + "\\..\\..\\..\\config\\01spacecalibrator\\calibration.json";
}
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;
}
@@ -61,7 +76,9 @@ static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream)
void SaveProfile(CalibrationContext &ctx)
{
std::ofstream file("openvr_space_calibration.json");
std::cout << "Saving profile to " << ConfigFileName() << std::endl;
std::ofstream file(ConfigFileName());
picojson::object profile;
profile["reference_tracking_system"].set<std::string>(ctx.referenceTrackingSystem);
@@ -111,3 +128,41 @@ static void UpgradeProfileV1(CalibrationContext &ctx)
file.close();
std::remove("openvr_space_calibration.txt");
}
void WriteActivateMultipleDriversToConfig()
{
std::string configPath = vr::VR_RuntimePath();
configPath += "\\..\\..\\..\\config\\steamvr.vrsettings";
std::ifstream ifile(configPath);
if (!ifile.good())
throw std::runtime_error("failed to read steamvr.vrsettings");
picojson::value v;
std::string err = picojson::parse(v, ifile);
if (!err.empty())
throw std::runtime_error(err);
ifile.close();
if (!v.is<picojson::object>())
throw std::runtime_error("steamvr.vrsettings is empty");
auto &root = v.get<picojson::object>();
if (!root["steamvr"].is<picojson::object>())
throw std::runtime_error("steamvr.vrsettings is missing \"steamvr\" key");
auto &steamvr = root["steamvr"].get<picojson::object>();
const bool tru = true; // MSVC picks the wrong specialization when passing a literal...
steamvr["activateMultipleDrivers"].set<bool>(tru);
std::ofstream ofile(configPath);
if (!ofile.good())
throw std::runtime_error("failed to write steamvr.vrsettings");
v.serialize(std::ostream_iterator<char>(ofile), true);
std::cout << "Successfully set activateMultipleDrivers to true" << std::endl;
}
+1
View File
@@ -4,3 +4,4 @@
void LoadProfile(CalibrationContext &ctx);
void SaveProfile(CalibrationContext &ctx);
void WriteActivateMultipleDriversToConfig();
+93
View File
@@ -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;
}
+18
View File
@@ -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;
};
+308 -12
View File
@@ -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,49 +75,210 @@ 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_SendVRScrollEvents, true);
std::string iconPath = cwd;
iconPath += "\\icon.png";
vr::VROverlay()->SetOverlayFromFile(overlayThumbnailHandle, iconPath.c_str());
}
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");
}
}
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;
vr::VROverlay()->ShowKeyboardForOverlay(
overlayMainHandle, vr::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine,
"Space Calibrator Overlay", sizeof buf, buf, false, 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_Scroll:
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_ImplGlfw_SetReadMouseFromGlfw(!dashboardVisible);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
BuildMainWindow();
BuildMainWindow(dashboardVisible);
ImGui::Render();
glBindFramebuffer(GL_FRAMEBUFFER, fboHandle);
glViewport(0, 0, width, height);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboHandle);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glfwSwapBuffers(glfwWindow);
glfwWaitEventsTimeout(CalCtx.wantedUpdateInterval);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
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) width, (float) height };
vr::VROverlay()->SetOverlayTexture(overlayMainHandle, &vrTex);
vr::VROverlay()->SetOverlayMouseScale(overlayMainHandle, &mouseScale);
}
glfwWaitEventsTimeout(dashboardVisible ? 0.0 : CalCtx.wantedUpdateInterval);
}
}
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);
//CreateConsole();
HandleCommandLine(lpCmdLine);
if (!glfwInit())
{
@@ -112,8 +291,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 +320,108 @@ 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)
{
printf("%s", vr::VR_RuntimePath());
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
{
WriteActivateMultipleDriversToConfig();
ret = 0;
}
catch (std::runtime_error &e)
{
std::cerr << "Failed to set activateMultipleDrivers: " << 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">
+26 -12
View File
@@ -9,6 +9,8 @@
#include <algorithm>
#include <imgui/imgui.h>
#define VERSION_STRING "0.7"
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,14 @@ void BuildMainWindow()
if (CalCtx.state == CalibrationState::None)
{
float width = ImGui::GetWindowContentRegionWidth();
float scale = 1.0f;
float width = ImGui::GetWindowContentRegionWidth(), scale = 1.0f;
if (CalCtx.validProfile)
{
width -= style.FramePadding.x * 2.0f;
scale = 2.0f / 3.0f;
width -= style.FramePadding.x * 4.0f;
scale = 1.0f / 3.0f;
}
if (ImGui::Button("Start New Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
if (ImGui::Button("Start Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
{
ImGui::OpenPopup("Calibration Progress");
StartCalibration();
@@ -77,10 +78,18 @@ 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.calibratedRotation = Eigen::Vector3d();
CalCtx.calibratedTranslation = Eigen::Vector3d();
CalCtx.validProfile = false;
}
}
}
else if (CalCtx.state == CalibrationState::Editing)
@@ -99,7 +108,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 +123,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 -1
View File
@@ -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

@@ -0,0 +1,6 @@
{
"alwaysActivate": true,
"name" : "01spacecalibrator",
"directory" : "",
"resourceOnly" : false
}
@@ -0,0 +1,5 @@
{
"jsonid" : "vrresources",
"statusicons" : {
}
}
@@ -0,0 +1,4 @@
{
"driver_01spacecalibrator" : {
}
}
+27
View File
@@ -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();
}
+75
View File
@@ -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;
};
+220
View File
@@ -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);
}
}
+53
View File
@@ -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();
+28
View File
@@ -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);
}
+24
View File
@@ -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()
}
};
+24
View File
@@ -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
View File
@@ -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) { }
};
}
+3 -8
View File
@@ -10,7 +10,6 @@ This is **beta software** and may not work for you. A quick video walkthrough of
If you don't already run a setup with multiple device types, see [Setting up SteamVR](#setting-up-steamvr).
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.
@@ -19,7 +18,8 @@ If you don't already run a setup with multiple device types, see [Setting up Ste
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.
Next time you run SteamVR and OpenVR-InputEmulator it will load the calibration automatically and apply it to any Vive devices you turn on.
Next time you run SteamVR, open OpenVR-SpaceCalibrator and it will load the calibration automatically and apply it devices you turn on.
### Setting up SteamVR
@@ -35,15 +35,10 @@ 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.
### 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.
1. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.
## The math
+192
View File
@@ -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
+81
View File
@@ -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.
+186
View File
@@ -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.
+20
View File
@@ -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);
+4
View File
@@ -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.
+22 -13
View File
@@ -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()
+2
View File
@@ -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);
+1 -1
View File
@@ -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"
-484
View File
@@ -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
-229
View File
@@ -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
File diff suppressed because it is too large. Load diff