Skip to content

Commit

Permalink
Version 1.1 beta1: Fixed installer, updated documentation and some ot…
Browse files Browse the repository at this point in the history
…her bugfixes and improvements.
  • Loading branch information
matzman666 committed Nov 5, 2017
1 parent c835165 commit 3b5caa4
Show file tree
Hide file tree
Showing 18 changed files with 702 additions and 259 deletions.
123 changes: 84 additions & 39 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

An OpenVR driver that allows to create virtual controllers, emulate controller input, enable motion compensation, manipulate poses of existing controllers and remap buttons. Includes a dashboard to configure some settings directly in VR, a command line client for more advanced settings, and a client-side library to support development of third-party applications.

![Example Screenshot](https://raw.githubusercontent.com/matzman666/OpenVR-InputEmulator/master/docs/screenshots/InVRScreenshot.png)
![Example Screenshot](docs/screenshots/InVRScreenshot.png)

The OpenVR driver hooks into the HTC Vive lighthouse driver and allows to modify any pose updates or button/axis events coming from the Vive controllers before they reach the OpenVR runtime. Due to the nature of this hack the driver may break when Valve decides to update the driver-side OpenVR API.

Expand Down Expand Up @@ -42,7 +42,7 @@ Download the newest command-line client from the [release section](https://githu

## Top Page:

![Root Page](https://raw.githubusercontent.com/matzman666/OpenVR-InputEmulator/master/docs/screenshots/DeviceManipulationPage.png)
![Root Page](docs/screenshots/DeviceManipulationPage.png)

- **Identify**: Sends a haptic pulse to the selected device (Devices without haptic feedback like the Vive trackers can be identified by a flashing white light).
- **Status**: Shows the current status of the selected device.
Expand All @@ -55,17 +55,18 @@ Download the newest command-line client from the [release section](https://githu
- **Device Offsets**: Allows to add translation or rotation offsets to the selected device.
- **Motion Compensation Settings**: Allows to configure motion compensation mode.
- **Render Model**: Shows a render model at the device position (experimental).
- **Input Remapping**: Allows to re-map input coming from controller buttons, joysticks or touchpads.
- **Profile**: Allows to apply/define/delete device offsets/motion compensation profiles.

### Redirect Mode

Redirect mode allows to redirect the pose updates and controller events from one controller to another. To enable it select the device from with the pose updates/controller events should be redirected, then set the device mode to "Redirect to" and select the device that should be the redirect target from the combo box on the right, and at last press 'Apply'.

Redirect mode can be temporarily suspended by pressing the system button on either the source or target device.
Redirect mode can be temporarily suspended by re-mapping a controller button to a "suspend" action on the input remapping page.

## Device Offsets Page:

![Device Offsets Page](https://raw.githubusercontent.com/matzman666/OpenVR-InputEmulator/master/docs/screenshots/DeviceOffsetsPage.png)
![Device Offsets Page](docs/screenshots/DeviceOffsetsPage.png)

- **Enable Offsets**: Enable/disable device offsets.
- **WorldFormDriver Offsets**: Allows to add offsets to the 'WorldFromDriver' transformations.
Expand All @@ -75,13 +76,85 @@ Redirect mode can be temporarily suspended by pressing the system button on eith

## Motion Compensation Settings Page:

![Motion Compensation Settings Page](https://raw.githubusercontent.com/matzman666/OpenVR-InputEmulator/master/docs/screenshots/MotionCompensationPage.png)
![Motion Compensation Settings Page](docs/screenshots/MotionCompensationPage.png)

**Vel/Acc Compensation Mode**: How should reported velocities and acceleration values be adjusted. The problem with only adjusting the headset position is that pose prediction also takes velocity and acceleration into accound. As long as the reported values to not differ too much from the real values, pose prediction errors are hardly noticeable. But with fast movements of the motion platform the pose prediction error can be noticeable. Available modes are:
- **Disabled**: Do not adjust velocity/acceration values.
- **Set Zero**: Set all velocity/acceleration values to zero. Most simple form of velocity/acceleration compensation.
- **Use Reference Tracker**: Substract the velocity/acceleration values of the motion compensation reference tracker/controller from the values reported from the headset. Most accurate form of velocity/acceleration compensation. However, it requires that the reference tracker/controller is as closely mounted to the head position as possible. The further away it is from the head position the larger the error.
- **Linear Approximation w/ Moving Average (Experimental)**: Uses linear approximation to estimate the velocity/acceleration values. The used formula is: (current_position - last_position) / time_difference. To reduce jitter the average over the last few values is used.
- **Moving Average Window**: How many values are used for calculating the average.
- **Kalman Filter (Experimental)**: The position values are fed into a kalman filter which then outputs a velocity value. The kalman filter implementation is based on the filter described [here](https://en.wikipedia.org/wiki/Kalman_filter#Example_application.2C_technical).
- **Process/Observation Noise**: Parameters used to fine-tune the kalman filter.

## Input Remapping Page:

![Input Remapping Page](docs/screenshots/InputRemappingPage.png)

Lists all available controller inputs (as reported by OpenVR) and their remapping statuses.

### Digital Input Settings:

![Digital Input Settings Page](docs/screenshots/DigitalInputPage.png)

- **Normal Press**: The configured key binding is send when the user normally presses a button (or in other words, when the input is neither a long nor a double press).
- **Touch as Click**: Registers a button touch as a button click. Can be used to simulate a touchpad click when the user only touches the touchpad.
- **Long Press**: The configured key binding is send when the user presses a button longer as the specified treshold.
- **Immediate Key Release**: The button down event for the double click event is immediately followed by a button up event. Useful for situations where a program only reacts on button up events (e.g. the SteamVR dashboard).
- **Double Press**: The configured key binding is send when two consecutive button presses happen within the specified time threshold.
- **Immediate Key Release**: The button down event for the double click event is immediately followed by a button up event. Useful for situations where a program only reacts on button up events (e.g. the SteamVR dashboard).

Attention: When long and double presses are enabled normal controller input may be delayed because I first need to wait the specified thresholds before I can send a normal key event.

#### Digital Binding:

![Digital Binding Page](docs/screenshots/DigitalBindingPage.png)

Allows to configure a digital button binding. Available binding types are:

- **No Remapping**: Original binding is used.
- **Disabled**: Disables the button.
- **OpenVR**: Remap to another OpenVR controller button.
- **Keyboard**: Remap to a keyboard key.
- **Suspend Redirect Mode**: Allows to temporarily suspend controller redirect mode.

##### OpenVR

![Digital Binding Page - OpenVR](docs/screenshots/DigitalBindingOpenVRPage.png)

- **Controller**: Onto which controller should the input be redirected.
- **Button**: Onto which OpenVR button should the input be mapped.
- **Toggle Mode**: When the button is pressed longer than the specified threshold, the button state is toggled.
- **Auto Trigger**: The button state is constantly pressed and then unpressed with the specified frequency as long as the user keeps the button pressed.

##### Keyboard

![Digital Binding Page - Keyboard](docs/screenshots/DigitalBindingKeyboardPage.png)

- **Key**: Onto which keyboard key should the input be mapped.
- **Toggle Mode**: When the button is pressed longer than the specified threshold, the key state is toggled.
- **Auto Trigger**: The key state is constantly pressed and then unpressed with the specified frequency as long as the user keeps the button pressed.

### Analog Input Settings:

![Analog Input Settings Page](docs/screenshots/AnalogBindingPage.png)

Allows to configure an analog input. Available binding types are:

- **No Remapping**: Original binding is used.
- **Disabled**: Disables the analog input.
- **OpenVR**: Remap to another OpenVR controller axis.

##### OpenVR

![Analog Binding Page - OpenVR](docs/screenshots/AnalogBindingOpenVRPage.png)

- **Controller**: Onto which controller should the input be redirected.
- **Axis**: Onto which OpenVR axis should the input be mapped.
- **Invert X/Y Axis**: Inverts the x or y axis.
- **Swap X/Y**: Swaps the x and the y axis.
- **Dead Zone**: Allows to configure dead zones in the middle (left value) and at the edges (right value) of an axis. The deadzone in the middle is mapped to 0, and the deadzone at the edges is mapped to 1. All input between the deadzones is remapped to an interval of [0, 1].

- **Vel/Acc Compensation Mode**: How should reported velocities and acceleration values be adjusted. The problem with only adjusting the headset position is that pose prediction also takes velocity and acceleration into accound. As long as the reported values to not differ too much from the real values, pose prediction errors are hardly noticeable. But with fast movements of the motion platform the pose prediction error can be noticeable. Available modes are:
- **Disabled**: Do not adjust velocity/acceration values.
- **Set Zero**: Set all velocity/acceleration values to zero. Most simple form of velocity/acceleration compensation.
- **Use Reference Tracker**: Substract the velocity/acceleration values of the motion compensation reference tracker/controller from the values reported from the headset. Most accurate form of velocity/acceleration compensation. However, it requires that the reference tracker/controller is as closely mounted to the head position as possible. The further away it is from the head position the larger the error.
- **Linear Approximation (Experimental)**: Uses linear approximation to estimate the velocity/acceleration values. The used formula is: (current_position - last_position) / time_difference, however the resulting values do cause a lot of jitter and therefore they are divided by four to reduce jitter to an acceptable level.

## client_commandline commands:

Expand Down Expand Up @@ -187,26 +260,6 @@ setdeviceposition <virtualId> <x> <y> <z>

setdevicerotation <virtualId> <yaw> <pitch> <roll>.

### devicebuttonmapping

```
devicebuttonmapping <openvrId> [enable|disable]
```

Enables/disables device button mapping on the given device.

```
devicebuttonmapping <openvrId> add <buttonId> <mappedButtonId>
```

Adds a new button mapping to the given device. See [openvr.h](https://github.com/ValveSoftware/openvr/blob/master/headers/openvr.h#L600-L626) for available button ids.

```
devicebuttonmapping <openvrId> remove [<buttonId>|all]
```

Removes a button mapping from the given device.


## Client API

Expand Down Expand Up @@ -255,16 +308,8 @@ client_commandline.exe setdeviceconnection 0 1
client_commandline.exe setdeviceposition 0 -1 -1 -1
```

## Map the grip-button to the trigger-button and vice-versa on the controller with id 3

```
client_commandline.exe devicebuttonmapping 3 add 2 33
client_commandline.exe devicebuttonmapping 3 add 33 2
client_commandline.exe devicebuttonmapping 3 enable
```

## Initial Setup
### Download the LeapMotion SDK
### ~~Download the LeapMotion SDK~~ (Only needed by the now defunct project driver_leapmotion)
1. Goto https://developer.leapmotion.com/get-started
1. Click "Download Orion Beta"
1. Unzip the "LeapSDK" folder in the zip file into `OpenVR-InputEmulator/third-party/LeapSDK`
Expand Down
83 changes: 0 additions & 83 deletions client_commandline/src/client_commandline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,59 +452,6 @@ void setDeviceRotation(int argc, const char* argv[]) {
inputEmulator.setVirtualDevicePose(deviceId, pose);
}

void deviceButtonMapping(int argc, const char * argv[]) {
if (argc > 2 && std::strcmp(argv[2], "help") == 0) {
std::stringstream ss;
ss << "Usage: client_commandline.exe devicebuttonmapping <openvrId> [enable|disable]" << std::endl
<< " client_commandline.exe devicebuttonmapping <openvrId> add <buttonId> <mappedButtonId>" << std::endl
<< " client_commandline.exe devicebuttonmapping <openvrId> remove [<buttonId>|all]";
throw std::runtime_error(ss.str());
} else if (argc < 4) {
throw std::runtime_error("Error: Too few arguments.");
}
uint32_t deviceId = std::atoi(argv[2]);
uint32_t enable = 0;
uint32_t operation = 0;
uint32_t op1 = 0;
uint32_t op2 = 0;
if (std::strcmp(argv[3], "enable") == 0) {
enable = 1;
} else if (std::strcmp(argv[3], "disable") == 0) {
enable = 2;
} else if (std::strcmp(argv[3], "add") == 0) {
if (argc < 6) {
throw std::runtime_error("Error: Too few arguments.");
}
operation = 1;
op1 = std::atoi(argv[4]);
op2 = std::atoi(argv[5]);
} else if (std::strcmp(argv[3], "remove") == 0) {
if (argc < 5) {
throw std::runtime_error("Error: Too few arguments.");
}
if (std::strcmp(argv[4], "all") == 0) {
operation = 3;
} else {
operation = 2;
op1 = std::atoi(argv[4]);
}

} else {
throw std::runtime_error("Error: Unknown button mapping command");
}
vrinputemulator::VRInputEmulator inputEmulator;
inputEmulator.connect();
if (enable > 0) {
inputEmulator.enableDeviceButtonMapping(deviceId, enable == 1 ? true : false);
} else if (operation == 1) {
inputEmulator.addDeviceButtonMapping(deviceId, (vr::EVRButtonId)op1, (vr::EVRButtonId)op2);
} else if (operation == 2) {
inputEmulator.removeDeviceButtonMapping(deviceId, (vr::EVRButtonId)op1);
} else if (operation == 3) {
inputEmulator.removeAllDeviceButtonMappings(deviceId);
}
}

void deviceOffsets(int argc, const char * argv[]) {
if (argc > 2 && std::strcmp(argv[2], "help") == 0) {
std::stringstream ss;
Expand Down Expand Up @@ -602,36 +549,6 @@ void deviceOffsets(int argc, const char * argv[]) {
}
}

void deviceModes(int argc, const char * argv[]) {
if (argc > 2 && std::strcmp(argv[2], "help") == 0) {
std::stringstream ss;
ss << "Usage: client_commandline.exe devicemirrormode <openvrId> off" << std::endl
<< " client_commandline.exe devicemirrormode <openvrId> [mirror|redirect] <targetOpenvrId>";
throw std::runtime_error(ss.str());
} else if (argc < 4) {
throw std::runtime_error("Error: Too few arguments.");
}
/*uint32_t deviceId = std::atoi(argv[2]);
uint32_t mode;
uint32_t target = vr::k_unTrackedDeviceIndexInvalid;
if (std::strcmp(argv[3], "off") == 0) {
mode = 0;
} else if (std::strcmp(argv[3], "mirror") == 0) {
mode = 1;
} else if (std::strcmp(argv[3], "redirect") == 0) {
mode = 2;
}
if (mode > 0) {
if (argc < 5) {
throw std::runtime_error("Error: Too few arguments.");
}
target = std::atoi(argv[4]);
}
vrinputemulator::VRInputEmulator inputEmulator;
inputEmulator.connect();
inputEmulator.setDeviceMirrorMode(deviceId, mode, target);*/
}




Expand Down
4 changes: 0 additions & 4 deletions client_commandline/src/client_commandline.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ void setDevicePosition(int argc, const char* argv[]);

void setDeviceRotation(int argc, const char* argv[]);

void deviceButtonMapping(int argc, const char* argv[]);

void deviceOffsets(int argc, const char* argv[]);

void deviceModes(int argc, const char* argv[]);

void benchmarkIPC(int argc, const char* argv[]);
6 changes: 0 additions & 6 deletions client_commandline/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ void printHelp(int argc, const char* argv[]) {
<< " setdeviceconnection\t\tSets the connection state of a virtual device" << std::endl
<< " setdeviceposition\t\tSets the position of a virtual device" << std::endl
<< " setdevicerotation\t\tSets the rotation of a virtual device" << std::endl
<< " devicebuttonmapping\t\tConfigures the device button mapping" << std::endl
<< " devicetranslationoffset\tConfigure the device translation offset" << std::endl
<< " devicerotationoffset\t\tConfigure the device rotation offset" << std::endl
<< " devicemirrormode\t\tConfigure the device mirror mode" << std::endl
<< " benchmarkipc\t\t\tipc benchmarks" << std::endl;
}

Expand Down Expand Up @@ -66,12 +64,8 @@ int main(int argc, const char* argv[]) {
setDevicePosition(argc, argv);
} else if (std::strcmp(argv[1], "setdevicerotation") == 0) {
setDeviceRotation(argc, argv);
} else if (std::strcmp(argv[1], "devicebuttonmapping") == 0) {
deviceButtonMapping(argc, argv);
} else if (std::strcmp(argv[1], "deviceoffsets") == 0) {
deviceOffsets(argc, argv);
} else if (std::strcmp(argv[1], "devicemodes") == 0) {
deviceModes(argc, argv);
} else if (std::strcmp(argv[1], "benchmarkipc") == 0) {
benchmarkIPC(argc, argv);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ MyStackViewPage {
spacing: 16

MyText {
text: "Active Zone:"
text: "Dead Zone:"
Layout.preferredWidth: 180
Layout.rightMargin: 12
}
Expand Down
4 changes: 2 additions & 2 deletions client_overlay/bin/win64/res/qml/MyRangeSlider.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ RangeSlider {
implicitHeight: 8
width: rangeSlider.availableWidth
height: implicitHeight
color: "#cccccc"
radius: 8
color: "#2c435d"

Rectangle {
x: rangeSlider.first.visualPosition * parent.width
width: rangeSlider.second.visualPosition * parent.width - x
height: parent.height
color: "#cccccc"
color: "#2c435d"
radius: 8
}
}
Expand Down
12 changes: 5 additions & 7 deletions client_overlay/src/overlaycontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ std::map<int, const char*> OverlayController::_openVRButtonNames = {

std::vector<std::pair<std::string, WORD>> OverlayController::_keyboardVirtualCodes = {
{ "<None>", 0x00 },
{ "Left Mouse Button", VK_LBUTTON },
/*{ "Left Mouse Button", VK_LBUTTON },
{ "Right Mouse Button", VK_RBUTTON },
{ "Middle Mouse Button", VK_MBUTTON },
{ "Middle Mouse Button", VK_MBUTTON },*/
{ "Backspace", VK_BACK },
{ "Tab", VK_TAB },
{ "Clear", VK_CLEAR },
Expand Down Expand Up @@ -745,23 +745,21 @@ QString OverlayController::openvrAxisToString(unsigned deviceId, unsigned axisId
vr::ETrackedPropertyError pError;
auto axisType = vr::VRSystem()->GetInt32TrackedDeviceProperty(deviceId, (vr::ETrackedDeviceProperty)((int)vr::Prop_Axis0Type_Int32 + axisId), &pError);
if (pError == vr::TrackedProp_Success && axisType != vr::k_eControllerAxis_None) {
name.append(" (");
switch (axisType) {
case vr::k_eControllerAxis_Trigger:
name.append("Trigger)");
name.append(" (Trigger)");
break;
case vr::k_eControllerAxis_TrackPad:
name.append("TrackPad)");
name.append(" (TrackPad)");
break;
case vr::k_eControllerAxis_Joystick:
name.append("Joystick)");
name.append(" (Joystick)");
break;
default:
LOG(INFO) << "AxisType: " << axisType;
name.append("<unknown>)");
break;
}
name.append(")");
}
}
return name;
Expand Down
2 changes: 1 addition & 1 deletion client_overlay/src/overlaycontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class OverlayController : public QObject {
public:
static constexpr const char* applicationKey = "matzman666.VRInputEmulator";
static constexpr const char* applicationName = "VR Input Emulator";
static constexpr const char* applicationVersionString = "v1.1";
static constexpr const char* applicationVersionString = "v1.1 beta1";

private:
vr::VROverlayHandle_t m_ulOverlayHandle = vr::k_ulOverlayHandleInvalid;
Expand Down
Binary file added docs/screenshots/AnalogBindingOpenVRPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/AnalogBindingPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/DeviceManipulationPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/DigitalBindingKeyboardPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/DigitalBindingOpenVRPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/DigitalBindingPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/DigitalInputPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/InputRemappingPage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3b5caa4

Please sign in to comment.