Skip to content

Commit

Permalink
Add functions to read calibration from registry
Browse files Browse the repository at this point in the history
refs #20 - add 'tablet mode' executable that's independent of OpenXR
  • Loading branch information
fredemmott committed Jan 5, 2023
1 parent 5c83d2d commit 989fb1d
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 27 deletions.
89 changes: 65 additions & 24 deletions src/APILayer/VirtualTouchScreenSink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,33 @@
namespace HandTrackedCockpitClicking {

VirtualTouchScreenSink::VirtualTouchScreenSink(
const std::shared_ptr<OpenXRNext>& oxr,
XrSession session,
XrTime nextDisplayTime,
XrSpace viewSpace) {
Calibration calibration,
DWORD targetProcessID)
: mCalibration(calibration), mTargetProcessID(targetProcessID) {
DebugPrint(
"Initialized virtual touch screen - PointerSink: {}; ActionSink: {}",
IsPointerSink(),
IsActionSink());

UpdateMainWindow();
}

VirtualTouchScreenSink::VirtualTouchScreenSink(
const std::shared_ptr<OpenXRNext>& oxr,
XrSession session,
XrTime nextDisplayTime,
XrSpace viewSpace)
: VirtualTouchScreenSink(
CalibrationFromOpenXR(oxr, session, nextDisplayTime, viewSpace).value(),
GetCurrentProcessId()) {
}

std::optional<VirtualTouchScreenSink::Calibration>
VirtualTouchScreenSink::CalibrationFromOpenXR(
const std::shared_ptr<OpenXRNext>& oxr,
XrSession session,
XrTime nextDisplayTime,
XrSpace viewSpace) {
XrViewLocateInfo viewLocateInfo {
.type = XR_TYPE_VIEW_LOCATE_INFO,
.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
Expand All @@ -57,42 +76,62 @@ VirtualTouchScreenSink::VirtualTouchScreenSink(
&viewCount,
views.data())) {
DebugPrint("Failed to find FOV");
return;
return {};
}

const auto eyeFov = views[0].fov;

auto calibration = CalibrationFromOpenXRFOV(eyeFov);

DebugPrint(
"Reported eye FOV: L {} R {} U {} D {} (input FOV {}x{}) - tracking origin "
"at ({}, "
"{})",
eyeFov.angleLeft,
eyeFov.angleRight,
eyeFov.angleUp,
eyeFov.angleDown,
calibration.mWindowInputFov.x,
calibration.mWindowInputFov.y,
calibration.mWindowInputFovOrigin0To1.x,
calibration.mWindowInputFovOrigin0To1.y);
return calibration;
}

VirtualTouchScreenSink::Calibration
VirtualTouchScreenSink::CalibrationFromOpenXRFOV(const XrFovf& eyeFov) {
// ideally this should be the sum of left+right and up+down FOVs - which
// aren't symmetric - but this seems to match what DCS does

mWindowInputFov = {
XrVector2f windowInputFov {
2 * std::max(std::abs(eyeFov.angleRight), std::abs(eyeFov.angleLeft)),
2 * std::abs(eyeFov.angleUp),
};

mFovOrigin0To1 = {
XrVector2f fovOrigin0To1 {
0.5,
0.5,
};

DebugPrint(
"Reported eye FOV: L {} R {} U {} D {} (input FOV {}x{}) - tracking origin "
"at ({}, "
"{})",
eyeFov.angleLeft,
eyeFov.angleRight,
eyeFov.angleUp,
eyeFov.angleDown,
mWindowInputFov.x,
mWindowInputFov.y,
mFovOrigin0To1.x,
mFovOrigin0To1.y);
return {windowInputFov, fovOrigin0To1};
}

UpdateMainWindow();
std::optional<VirtualTouchScreenSink::Calibration>
VirtualTouchScreenSink::CalibrationFromConfig() {
if (!Config::HaveSavedFOV) {
return {};
}

const XrFovf eyeFov {
.angleLeft = Config::LeftEyeFOVLeft,
.angleRight = Config::LeftEyeFOVRight,
.angleUp = Config::LeftEyeFOVUp,
.angleDown = Config::LeftEyeFOVDown,
};
return CalibrationFromOpenXRFOV(eyeFov);
}

void VirtualTouchScreenSink::UpdateMainWindow() {
mThisProcess = GetCurrentProcessId();
mConsoleWindow = GetConsoleWindow();
EnumWindows(
&VirtualTouchScreenSink::EnumWindowCallback,
Expand All @@ -114,7 +153,7 @@ VirtualTouchScreenSink::EnumWindowCallback(HWND hwnd, LPARAM lparam) {

DWORD processID {};
GetWindowThreadProcessId(hwnd, &processID);
if (processID != self->mThisProcess) {
if (processID != self->mTargetProcessID) {
return TRUE;
}

Expand Down Expand Up @@ -187,9 +226,11 @@ bool VirtualTouchScreenSink::RotationToCartesian(
// Flipped because screen X is left-to-right, which is a rotation around the Y
// axis

const auto screenX = mFovOrigin0To1.x + (rotation.y / mWindowInputFov.x);
const auto screenX = mCalibration.mWindowInputFovOrigin0To1.x
+ (rotation.y / mCalibration.mWindowInputFov.x);
// OpenXR has Y origin in bottom left, screeen has it in top left
const auto screenY = mFovOrigin0To1.y - (rotation.x / mWindowInputFov.y);
const auto screenY = mCalibration.mWindowInputFovOrigin0To1.y
- (rotation.x / mCalibration.mWindowInputFov.y);

if (screenX < 0 || screenX > 1 || screenY < 0 || screenY > 1) {
return false;
Expand Down
22 changes: 19 additions & 3 deletions src/APILayer/VirtualTouchScreenSink.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ namespace HandTrackedCockpitClicking {

class VirtualTouchScreenSink final {
public:
struct Calibration {
XrVector2f mWindowInputFov {};
XrVector2f mWindowInputFovOrigin0To1 {};
};

VirtualTouchScreenSink(Calibration, DWORD targetProcessID);
VirtualTouchScreenSink(
const std::shared_ptr<OpenXRNext>& oxr,
XrSession session,
Expand All @@ -44,21 +50,31 @@ class VirtualTouchScreenSink final {
static bool IsActionSink();
static bool IsPointerSink();

VirtualTouchScreenSink() = delete;

static std::optional<Calibration> CalibrationFromOpenXR(
const std::shared_ptr<OpenXRNext>& oxr,
XrSession session,
XrTime nextDisplayTime,
XrSpace viewSpace);

static Calibration CalibrationFromOpenXRFOV(const XrFovf& eyeFov);
static std::optional<Calibration> CalibrationFromConfig();

private:
void Update(const InputState& hand);
bool RotationToCartesian(const XrVector2f& rotation, XrVector2f* cartesian);
void UpdateMainWindow();
static BOOL CALLBACK EnumWindowCallback(HWND hwnd, LPARAM lparam);

DWORD mThisProcess;
DWORD mTargetProcessID;
HWND mWindow {};
HWND mConsoleWindow {};
XrVector2f mWindowSize {};
RECT mWindowRect {};
XrVector2f mScreenSize;

XrVector2f mWindowInputFov {};
XrVector2f mFovOrigin0To1 {};
Calibration mCalibration {};

bool mLeftClick {false};
bool mRightClick {false};
Expand Down

0 comments on commit 989fb1d

Please sign in to comment.