Merge branch 'master' into alpha-kung

This commit is contained in:
Kung-vr
2019-01-25 00:14:33 +09:00
26 changed files with 780 additions and 40 deletions
+20 -5
View File
@@ -1,8 +1,24 @@
language: cpp
dist: xenial
compiler:
- clang
- gcc
matrix:
include:
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env:
- QMAKE_SPEC=linux-g++
- os: linux
env:
- QMAKE_SPEC=linux-clang
before_install:
- python ./build_scripts/run-clang-format.py ./src -r --color always
install:
- sudo add-apt-repository ppa:kubuntu-ppa/backports -y
@@ -10,7 +26,6 @@ install:
- sudo apt-get install build-essential qtbase5-dev qttools5-dev qtdeclarative5-dev qtmultimedia5-dev qt5-default qttools5-dev-tools
script:
- python ./build_scripts/run-clang-format.py ./src -r --color always
- mkdir build && cd build
- qmake ..
- qmake .. -spec $QMAKE_SPEC
- make
+39 -15
View File
@@ -1,5 +1,6 @@
![language](https://img.shields.io/badge/Language-C%2B%2B11%2C%20QML-green.svg) ![dependencies](https://img.shields.io/badge/Dependencies-OpenVR%2C%20Qt5-green.svg)
![language](https://img.shields.io/badge/Language-C%2B%2B17%2C%20QML-green.svg) ![dependencies](https://img.shields.io/badge/Dependencies-OpenVR%2C%20Qt5%2C%20Python3-green.svg)
![license_gpl3](https://img.shields.io/badge/License-GPL%203.0-green.svg)
[![Build status](https://ci.appveyor.com/api/projects/status/8oivf5xws6vsq2x3/branch/master?svg=true)](https://ci.appveyor.com/project/icewind1991/openvr-advancedsettings/branch/master)
[![Build Status](https://travis-ci.org/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings.svg?branch=master)](https://travis-ci.org/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings)
@@ -7,6 +8,7 @@
> * [Usage](#usage)
> * [Installer](#installer)
> * [Standalone](#standalone)
> * [Bindings](#bindings)
> * [Command Line Arguments](#command_line_arguments)
> * [Logging Config](#logging_config)
> * [Preview Builds](#preview_builds)
@@ -27,7 +29,6 @@
> * [Building on Windows](#building_on_windows)
> * [Building on Linux](#building_on_linux)
> * [Notes](#notes)
> * [Known Bugs](#known_bugs)
> * [License](#license)
<a name="top"></a>
@@ -41,7 +42,7 @@ Adds an overlay to the OpenVR dashboard that allows access to advanced settings.
# Features
- Set supersampling values.
- Enable/disable asynchronous and interleaved reprojection.
- Enable/disable motion smoothing and advanced supersample filtering.
- Save supersampling and reprojection settings into profiles.
- Change several chaperone settings not accessible via SteamVR settings (to e.g. make it completely invisible).
- Chaperone Proximity Warning: Several warning methods can be configured.
@@ -53,7 +54,7 @@ Adds an overlay to the OpenVR dashboard that allows access to advanced settings.
- Mute/unmute and set volume of audio mirror device.
- Mute/unmute and set volume of microphone device.
- Implements push-to-talk and allows to configure push-to-talk profiles.
- Desktop mode shows a window on the desktop instead of a vr overlay.
- Desktop mode shows a window on the desktop instead of a VR overlay.
- Revive settings support (Requires [Revive 1.0.4+](https://github.com/LibreVR/Revive) for full functionality).
- VR Keyboard Input Utilities
- Simple Alarm Clock
@@ -67,24 +68,46 @@ Adds an overlay to the OpenVR dashboard that allows access to advanced settings.
Download the newest installer from the [release section](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/releases) and execute it.
If you have an older standalone version installed, delete the old application folder first.
If you have an older standalone version installed, the installer will automatically uninstall the old version and install the new version.
<a name="standalone"></a>
## Standalone
I am not currently providing standalone Archives if you want a standalone version you can:
Download the newest standalone archive from the [release section](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/releases)and unpack the archive.
Download the newest standalone archive from the [release section](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/releases) and unpack the archive.
To install for the first time simply start AdvancedSettings.exe once while SteamVR is running. It will register with SteamVR and automatically starts whenever SteamVR starts (Can be disabled in the settings).
To upgrade an existing installation first stop SteamVR and delete the old application folder (or override it). Then start SteamVR and run AdvancedSettings.exe once.
<a name="bindings"></a>
## Bindings
Advanced Settings supports the OpenVR IVRInput API. In order to make the bindings interface visible, change the `matzman666.AdvancedSettings.vrappconfig` in `C:\Program Files (x86)\Steam\config\vrappconfig` to have a `last_launch_time` close to the current date (in [Unix time](https://en.wikipedia.org/wiki/Unix_time)). If in doubt, try using the value from [this](https://time.is/Unix_time_now) site. Running the application normally will now make it show up in the bindings interface.
Alternatively, if the above doesn't work, run the `bindingsinterface.bat` file from the install directory. After you're done configuring your bindings, close SteamVR and start it up again. You are now using your new bindings. Advanced Settings will not show up in the bindings menu unless you're actively running the application with `bindingsinterface.bat`. Advanced Settings will not work normally while running with `bindingsinterface.bat`.
The above two solutions are workarounds to a bug in the OpenVR API.
After doing one of the above workarounds, when SteamVR starts click the menu -> Settings -> Controller Binding. You can also visit [this](127.0.0.1:8998/dashboard/controllerbinding.html) site in your internet browser. It's the same as the built in SteamVR bindings menu. SteamVR must be running for it to work.
By default no buttons are bound.
The following actions currently exist:
| Action | Type | Explanation |
| ------------- | ------------- | ------------ |
| NextSong | Binary/Button | The same as using the media keys. Tells a media player to play the next song.|
| PreviousSong | Binary/Button | The same as using the media keys. Tells a media player to play the previous song. |
| pausePlaySong | Binary/Button | The same as using the media keys. Tells the media player to press play/pause. |
| stopSong | Binary/Button | The same as using the media keys. Tells the media player to stop playback. |
<a name="command_line_arguments"></a>
## Command Line Arguments
The application (`AdvancedSettings.exe`) can be run with the following five optional arguments:
The application (`AdvancedSettings.exe`) can be run with the following optional arguments:
`"-desktop"`: Creates a settings window on the desktop as well as in VR. Running `startdesktopmode.bat` in the install directory has the same effect.
`"-desktop"`: Creates a settings window on the desktop, but not in VR. Running `startdesktopmode.bat` in the install directory has the same effect.
`"-nosound"`: Forces sound effects off.
@@ -94,6 +117,8 @@ The application (`AdvancedSettings.exe`) can be run with the following five opti
`"-removemanifest"`: Force uninstalls the `.vrmanifest`. This should be done every time the application is uninstalled. On Windows it is automatically done by the uninstaller. The program will exit early when this flag is set.
`"-bindingsinterface"`: Makes Advanced Settings show up in the SteamVR bindings interface. This is necessary for binding keys to actions. This is the same as running `bindingsinterface.bat` from the executable directory. The program will not exit when this is set. No normal functionality is available except using the bindings interface. Bindings set with this active will be available when this isn't active.
In addition, the application can receive the command line arguments from the [Easylogging++ library](https://github.com/zuhd-org/easyloggingpp#application-arguments).
<a name="logging_config"></a>
@@ -104,7 +129,9 @@ The logging output of the [Easylogging++ library](https://github.com/zuhd-org/ea
<a name="preview_builds"></a>
## Preview builds
If you want to try latest and greatest unreleased features, you can download latest changes in the alpha branches of the repository.
If you want to try latest and greatest unreleased features, you can download latest from the CI (Continuous Integration) server for [Windows](https://ci.appveyor.com/project/icewind1991/openvr-advancedsettings/branch/master). The Linux CI does not provide binary artifacts.
These version are not stable and this should be considered for advanced users only.
<a name="documentation"></a>
# Documentation
@@ -201,6 +228,8 @@ Allows to temporarily move and rotate the center of the playspace. This allows t
![Revive Page](docs/screenshots/RevivePage.png)
**The Revive page is not currently being maintained. Features may not be stable, performant or actually work.**
The Revive page is only visible when the [Revive overlay](https://github.com/LibreVR/Revive) is installed. In case an installed Revive overlay is not correctly detected you can force the Revive page in the settings.
Any changes to controller settings are immediately applied by Revive (Requires Revive 1.0.4+).
@@ -286,11 +315,6 @@ If you want to contribute changes running `clang-format` is necessary. More deta
- You can modify the shutdown wait time when restarting SteamVR by opening restartvrserver.bat and changing the number behind "timeout /t" (unit is seconds).
<a name="known_bugs"></a>
# Known Bugs
- None yet.
<a name="license"></a>
# License
+21 -5
View File
@@ -5,7 +5,7 @@
#-------------------------------------------------
QT += core gui qml quick multimedia widgets
CONFIG += c++14
CONFIG += c++1z
DEFINES += ELPP_THREAD_SAFE ELPP_QT_LOGGING ELPP_NO_DEFAULT_LOG_FILE
@@ -20,8 +20,13 @@ TEMPLATE = app
#D9025: overriding '/W4' with '/W3'
QMAKE_CFLAGS_WARN_ON -= -W3
QMAKE_CXXFLAGS_WARN_ON -= -W3
#C4127 was in a third party file with no way to turn off.
#C4127 is a warning in qvarlengtharray.h that can not be turned off
#on the current version of MSVC.
QMAKE_CXXFLAGS += /W4 /wd4127
# The codecvt header being used in AudioManagerWindows.cpp is deprecated by the standard,
# but no suitable replacement has been standardized yet. It is possible to use the Windows
# specific MultiByteToWideChar() and WideCharToMultiByte() from <Windows.h>
DEFINES += _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
!*clang-msvc {
#win32-clang-msvc is unable to correctly build the first time
#with warnings as errors on. There seems to be an issue with the moc_predefs.h
@@ -31,7 +36,14 @@ TEMPLATE = app
}
}
win32-clang-msvc{
#clang-msvc does not enable the c++17 flag with qmake's c++1z flag.
QMAKE_CXXFLAGS += /std:c++17
}
*g++* {
#g++-7 is needed for C++17 features. travis does not supply this by default.
QMAKE_CXX = g++-7
QMAKE_CXXFLAGS += -Werror
}
@@ -58,8 +70,8 @@ SOURCES += src/main.cpp\
src/utils/ChaperoneUtils.cpp \
src/tabcontrollers/audiomanager/AudioManagerDummy.cpp \
src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp \
src/overlaycontroller/openvr_init.cpp
src/overlaycontroller/openvr_init.cpp \
src/ivrinput/ivrinput.cpp
HEADERS += src/overlaycontroller.h \
src/tabcontrollers/AudioTabController.h \
@@ -79,7 +91,11 @@ HEADERS += src/overlaycontroller.h \
src/utils/ChaperoneUtils.h \
src/tabcontrollers/audiomanager/AudioManagerDummy.h \
src/tabcontrollers/keyboardinput/KeyboardInputDummy.h \
src/overlaycontroller/openvr_init.h
src/overlaycontroller/openvr_init.h \
src/ivrinput/ivrinput_action.h \
src/ivrinput/ivrinput_manifest.h \
src/ivrinput/ivrinput_action_set.h \
src/ivrinput/ivrinput.h
win32 {
SOURCES += src/tabcontrollers/audiomanager/AudioManagerWindows.cpp \
Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 42 KiB

+6
View File
@@ -109,7 +109,13 @@ Section "Install" SecInstall
File "${BASEDIR}\LICENSE-GPL.txt"
File "${BASEDIR}\LICENSE-MIT.txt"
File "${BASEDIR}\LICENSE-VALVE.txt"
File "${BASEDIR}\*.exe"
;Any action manifests
File "${BASEDIR}\*.json"
;And their defaults
File "${BASEDIR}\default_action_manifests\*.json"
File "${THIRDDIR}\openvr\bin\win64\*.dll"
File "${BASEDIR}\*.dll"
File "${PACKAGEDIR}\*.bat"
+202
View File
@@ -0,0 +1,202 @@
#include "ivrinput.h"
#include <openvr.h>
#include <iostream>
#include <QStandardPaths>
#include <easylogging++.h>
namespace input
{
/*!
Wrapper around the IVRInput GetAnalogActionData with error handling.
The struct is created and zero initalized in this function instead of being
passed as reference since the size is currently only 28 bytes, and currently
only two bools are used from the entire struct.
MSVC on /O2 will likely completely optimize the function call away but even if
it isn't the struct will still need to be created somewhere, and with move
semantics it almost doesn't matter if the struct is created in the calling
function and passed as reference, or created in this function.
*/
vr::InputDigitalActionData_t getDigitalActionData( Action& action )
{
if ( action.type() != ActionType::Digital )
{
LOG( ERROR )
<< "Action was passed to IVRInput getDigitalActionData without "
"being a digital type. Action: "
<< action.name();
throw std::runtime_error(
"Action was passed to IVRInput getDigitalActionData without being "
"a digital type. See log for details." );
}
vr::InputDigitalActionData_t handleData = {};
const auto error = vr::VRInput()->GetDigitalActionData(
action.handle(),
&handleData,
sizeof( handleData ),
vr::k_ulInvalidInputValueHandle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting IVRInput Digital Action Data for handle "
<< action.name() << ". SteamVR Error: " << error;
}
return handleData;
}
/*!
Wrapper around the IVRInput GetAnalogActionData with error handling.
The struct is created and zero initalized in this function instead of being
passed as reference since the size is currently only 28 bytes, and currently
only two bools are used from the entire struct.
MSVC on /O2 will likely completely optimize the function call away but even if
it isn't the struct will still need to be created somewhere, and with move
semantics it almost doesn't matter if the struct is created in the calling
function and passed as reference, or created in this function.
*/
vr::InputAnalogActionData_t getAnalogActionData( Action& action )
{
if ( action.type() != ActionType::Analog )
{
LOG( ERROR )
<< "Action was passed to IVRInput getAnalogActionData without "
"being an analog type. Action: "
<< action.name();
throw std::runtime_error(
"Action was passed to IVRInput getAnalogActionData without being "
"an analog type. See log for details." );
}
vr::InputAnalogActionData_t handleData = {};
const auto error
= vr::VRInput()->GetAnalogActionData( action.handle(),
&handleData,
sizeof( handleData ),
vr::k_ulInvalidInputValueHandle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting IVRInput Digital Action Data for handle "
<< action.name() << ". SteamVR Error: " << error;
}
return handleData;
}
/*!
Gets the action state of an Action.
This will only return true the first time the button is released. It is
necessary to release the button and the push it again in order for this function
to return true again.
*/
bool isDigitalActionActivatedOnce( Action& action )
{
const auto handleData = getDigitalActionData( action );
return handleData.bState && handleData.bChanged;
}
/*!
Gets the action state of an Action.
This will continually return true while the button is held down.
*/
bool isDigitalActionActivatedConstant( Action& action )
{
const auto handleData = getDigitalActionData( action );
return handleData.bState;
}
/*!
Sets up the input systems.
Actions should be added to the initializer list before the body of the
constructor. Actions should be certain that the action name strings are
correctly input, and that the correct type is provided.
Wrong action names may not result in direct error messages, but just features
mystically not working.
*/
SteamIVRInput::SteamIVRInput()
: m_manifest(), m_mainSet( input_strings::k_setMain ),
m_nextTrack( input_strings::k_actionNextTrack, ActionType::Digital ),
m_previousTrack( input_strings::k_actionPreviousTrack,
ActionType::Digital ),
m_pausePlayTrack( input_strings::k_actionPausePlayTrack,
ActionType::Digital ),
m_stopTrack( input_strings::k_actionStopTrack, ActionType::Digital )
{
m_activeActionSet.ulActionSet = m_mainSet.handle();
m_activeActionSet.ulRestrictedToDevice = vr::k_ulInvalidInputValueHandle;
m_activeActionSet.nPriority = 0;
}
/*!
Returns true if the next media track should be played.
Will only return true the first time that the button is pressed. Holding the
button down will result in false until it has been released and pushed again.
*/
bool SteamIVRInput::nextSong()
{
return isDigitalActionActivatedOnce( m_nextTrack );
}
/*!
Returns true if the previous media track should be played.
Will only return true the first time that the button is pressed. Holding the
button down will result in false until it has been released and pushed again.
*/
bool SteamIVRInput::previousSong()
{
return isDigitalActionActivatedOnce( m_previousTrack );
}
/*!
Returns true if media playback should be paused/played.
Will only return true the first time that the button is pressed. Holding the
button down will result in false until it has been released and pushed again.
*/
bool SteamIVRInput::pausePlaySong()
{
return isDigitalActionActivatedOnce( m_pausePlayTrack );
}
/*!
Returns true if media playback should be stopped.
Will only return true the first time that the button is pressed. Holding the
button down will result in false until it has been released and pushed again.
*/
bool SteamIVRInput::stopSong()
{
return isDigitalActionActivatedOnce( m_stopTrack );
}
/*!
Updates the active action set(s).
Should be called every frame, or however often you want the input system to
update state.
*/
void SteamIVRInput::UpdateStates()
{
constexpr auto numberOfSets = 1;
const auto error = vr::VRInput()->UpdateActionState(
&m_activeActionSet, sizeof( m_activeActionSet ), numberOfSets );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR )
<< "Error during IVRInput action state update. OpenVR Error: "
<< error;
}
}
} // namespace input
+90
View File
@@ -0,0 +1,90 @@
#pragma once
#include <openvr.h>
#include "ivrinput_action.h"
#include "ivrinput_manifest.h"
#include "ivrinput_action_set.h"
namespace input
{
/*!
Responsible for controller input.
UpdateStates should be called every frame.
Binary actions should only have one function,
and they should reflect the expected behaviour. I.e. if a button being pressed
and held should only return true the first time, that logic should be in the
function.
An action in the IVRInput API is entered in the actions manifest. This is a
.json file that is included with the final binary.
Currently an Action is created with a string and a type. The type determines
which function should be used for getting information from the API. The type in
the actions manifest must match the type in the source code.
Actions should be added as member objects to SteamIVRInput and initialized in
the constructor. They should then make a small number of accessor functions
available for outside use. The internal structs of the IVRInput API are not
entirely stable, and should not be leaked outside this class.
The name of the actions manifest must be set in ivrinput_manifest.h.
*/
class SteamIVRInput
{
public:
SteamIVRInput();
void UpdateStates();
bool nextSong();
bool previousSong();
bool pausePlaySong();
bool stopSong();
// Destructor. There are no terminating calls for the IVRInput API, so it
// is left blank.
~SteamIVRInput() {}
// These have been explicitly deleted to make sure there are no attempts at
// copying the class in weird ways. It is not worth defining what should
// happen on copy because it simply shouldn't be done.
// They are declared public because compilers will give wrong error messages
// if they are private.
// Copy constructor
SteamIVRInput( const SteamIVRInput& ) = delete;
// Copy assignment
SteamIVRInput& operator=( const SteamIVRInput& ) = delete;
// Move constructor
SteamIVRInput( SteamIVRInput&& ) = delete;
// Move assignment
SteamIVRInput& operator=( const SteamIVRInput&& ) = delete;
private:
Manifest m_manifest;
ActionSet m_mainSet;
vr::VRActiveActionSet_t m_activeActionSet = {};
// Music player bindings
Action m_nextTrack;
Action m_previousTrack;
Action m_pausePlayTrack;
Action m_stopTrack;
};
/*!
The IVRInput system is _very_ finnicky about strings matching and if they don't
match there are usually no errors logged reflecting that. constexpr auto strings
should be used to refer to all action manifest strings.
*/
namespace input_strings
{
constexpr auto k_actionNextTrack = "/actions/main/in/NextTrack";
constexpr auto k_actionPreviousTrack = "/actions/main/in/PreviousTrack";
constexpr auto k_actionPausePlayTrack = "/actions/main/in/PausePlayTrack";
constexpr auto k_actionStopTrack = "/actions/main/in/StopTrack";
constexpr auto k_setMain = "/actions/main";
} // namespace input_strings
} // namespace input
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#include <openvr.h>
#include <easylogging++.h>
namespace input
{
/*!
The type of function that should be called to get data for the action.
The IVRInput API does not give explicit warnings when the wrong functions are
called. This enum is an attempt at runtime checking.
*/
enum class ActionType
{
Undefined,
Digital,
Analog,
};
/*!
Represents a single action from the actions manifest. Should be instantiated
with a name similar to that of the one in the actions manifest.
*/
class Action
{
public:
Action( const char* const actionName, const ActionType type )
: m_name( actionName ), m_type( type )
{
auto error = vr::VRInput()->GetActionHandle( actionName, &m_handle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting handle for '" << actionName
<< "'. OpenVR Error: " << error;
}
}
/*!
An API internal handle that identifies an action.
*/
vr::VRActionHandle_t handle() const noexcept
{
return m_handle;
}
/*!
The actions manfiest name of the action. Used for error reporting.
*/
std::string name() const noexcept
{
return m_name;
}
/*!
The type of the action. Used for runtime checking that the wrong functions
aren't called.
*/
ActionType type() const noexcept
{
return m_type;
}
private:
vr::VRActionHandle_t m_handle = 0;
const std::string m_name;
const ActionType m_type = ActionType::Undefined;
};
} // namespace input
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include <openvr.h>
#include <easylogging++.h>
namespace input
{
/*!
Represents an action set from the action manifest.
*/
class ActionSet
{
public:
ActionSet( const char* setName ) : m_name( setName )
{
auto error = vr::VRInput()->GetActionSetHandle( setName, &m_handle );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error getting handle for '" << setName
<< "'. OpenVR Error: " << error;
}
}
/*!
The actions manfiest name of the set. Used for error reporting.
*/
std::string name()
{
return m_name;
}
/*!
An API internal handle that identifies a set.
*/
vr::VRActionSetHandle_t handle()
{
return m_handle;
}
private:
const std::string m_name;
vr::VRActionSetHandle_t m_handle = 0;
};
} // namespace input
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <QStandardPaths>
#include <openvr.h>
#include <easylogging++.h>
namespace input
{
/*!
Initializes IVRInput to point at the correct manifest. Can't be done in the
constructor body since objects being initialized require this to be set.
*/
class Manifest
{
public:
Manifest()
{
QString actionManifestPath = QStandardPaths::locate(
QStandardPaths::AppDataLocation,
QStringLiteral( "action_manifest.json" ) );
auto error = vr::VRInput()->SetActionManifestPath(
actionManifestPath.toStdString().c_str() );
if ( error != vr::EVRInputError::VRInputError_None )
{
LOG( ERROR ) << "Error setting action manifest path: "
<< actionManifestPath << ". OpenVR Error: " << error;
}
}
// Explicitly deleted because this object should do nothing but run the
// constructor during initialization.
// Destructor left blank on purpose since there are no terminating calls.
~Manifest() {}
// Copy constructor
Manifest( const Manifest& ) = delete;
// Copy assignment
Manifest& operator=( const Manifest& ) = delete;
// Move constructor
Manifest( const Manifest&& ) = delete;
// Move assignment
Manifest& operator=( const Manifest&& ) = delete;
};
} // namespace input
+12
View File
@@ -46,6 +46,7 @@ constexpr auto kNoSound = "-nosound";
constexpr auto kNoManifest = "-nomanifest";
constexpr auto kInstallManifest = "-installmanifest";
constexpr auto kRemoveManifest = "-removemanifest";
constexpr auto kEnableBindingsInterface = "-bindingsinterface";
} // namespace argument
namespace manifest
@@ -357,6 +358,8 @@ int main( int argc, char* argv[] )
argc, argv, argument::kInstallManifest );
const bool removeManifest = argument::CheckCommandLineArgument(
argc, argv, argument::kRemoveManifest );
const bool bindingsInterface = argument::CheckCommandLineArgument(
argc, argv, argument::kEnableBindingsInterface );
// If a command line arg is set, make sure the logs reflect that.
LOG_IF( desktopMode, INFO ) << "Desktop mode enabled.";
@@ -364,6 +367,15 @@ int main( int argc, char* argv[] )
LOG_IF( noManifest, INFO ) << "vrmanifest disabled.";
LOG_IF( installManifest, INFO ) << "Install manifest enabled.";
LOG_IF( removeManifest, INFO ) << "Remove manifest enabled.";
LOG_IF( bindingsInterface, INFO ) << "Bindings interface enabled.";
if ( bindingsInterface )
{
// This is a temporary solution until Valve fixes overlays not
// showing up in the bindings interface. See function description for
// more info.
openvr_init::openBindingsMenu();
}
// It is important that either install_manifest or remove_manifest are true,
// otherwise the handleManifests function will not behave properly.
+33 -2
View File
@@ -32,7 +32,7 @@ OverlayController::OverlayController( bool desktopMode,
bool noSound,
QQmlEngine& qmlEngine )
: QObject(), m_desktopMode( desktopMode ), m_noSound( noSound ),
m_openVrInit()
m_openVrInit(), m_actions()
{
// Despite arguably being OpenVR init code, the call is still here because
// the TabController uses this directly. Offering it through OpenVR_Init
@@ -118,7 +118,6 @@ OverlayController::OverlayController( bool desktopMode,
nullptr, "OpenVR Advanced Settings Overlay", "Is OpenVR running?" );
throw std::runtime_error( std::string( "No Overlay interface" ) );
}
// Init controllers
m_steamVRTabController.initStage1();
m_chaperoneTabController.initStage1();
@@ -475,15 +474,47 @@ QPoint OverlayController::getMousePositionForEvent( vr::VREvent_Mouse_t mouse )
return QPoint( mouse.x, y );
}
/*!
Checks if an action has been activated and dispatches the related action if it
has been.
This function should probably be split into several functions that are specific
to a binding type as the amount of actions grows.
*/
void OverlayController::processInputBindings()
{
if ( m_actions.nextSong() )
{
m_utilitiesTabController.sendMediaNextSong();
}
if ( m_actions.previousSong() )
{
m_utilitiesTabController.sendMediaPreviousSong();
}
if ( m_actions.pausePlaySong() )
{
m_utilitiesTabController.sendMediaPausePlay();
}
if ( m_actions.stopSong() )
{
m_utilitiesTabController.sendMediaStopSong();
}
}
void OverlayController::OnTimeoutPumpEvents()
{
vr::VRSystem()->GetTimeSinceLastVsync( nullptr, &m_currentFrame );
if ( m_currentFrame > m_lastFrame )
{
if ( !vr::VRSystem() )
return;
m_actions.UpdateStates();
processInputBindings();
vr::VREvent_t vrEvent;
bool chaperoneDataAlreadyUpdated = false;
while ( pollNextEvent( m_ulOverlayHandle, &vrEvent ) )
+6 -1
View File
@@ -39,6 +39,8 @@
#include "tabcontrollers/UtilitiesTabController.h"
#include "tabcontrollers/AccessibilityTabController.h"
#include "ivrinput/ivrinput.h"
// application namespace
namespace advsettings
{
@@ -89,7 +91,9 @@ private:
// OpenVR_Init must be declared before any other class that uses OpenVR
// function calls since objects are initialized in order of declaration in
// the class.
OpenVR_Init m_openVrInit;
openvr_init::OpenVR_Init m_openVrInit;
input::SteamIVRInput m_actions;
public: // I know it's an ugly hack to make them public to enable external
// access, but I am too lazy to implement getters.
@@ -106,6 +110,7 @@ public: // I know it's an ugly hack to make them public to enable external
private:
QPoint getMousePositionForEvent( vr::VREvent_Mouse_t mouse );
void processInputBindings();
public:
OverlayController( bool desktopMode, bool noSound, QQmlEngine& qmlEngine );
+72 -2
View File
@@ -2,10 +2,13 @@
#include <openvr.h>
#include <QMessageBox>
#include "openvr_init.h"
#include <easylogging++.h>
#include "../ivrinput/ivrinput_manifest.h"
OpenVR_Init::OpenVR_Init()
namespace openvr_init
{
void initializeProperly()
{
// Loading the OpenVR Runtime
auto initError = vr::VRInitError_None;
vr::VR_Init( &initError, vr::VRApplication_Overlay );
if ( initError != vr::VRInitError_None )
@@ -22,6 +25,68 @@ OpenVR_Init::OpenVR_Init()
+ std::string(
vr::VR_GetVRInitErrorAsEnglishDescription( initError ) ) );
}
else
{
LOG( INFO ) << "OpenVR initialized successfully.";
}
}
/*!
Initializes OpenVR to be in the bindings menu and then exits.
This is needed because all applications initialized with OpenVR that aren't of
type vr::VRApplication_Scene do not show up the in bindings menu.
This is obviously an ugly hack and should be done away with as soon as Valve
fixes this issue.
Official Issues for this:
https://github.com/ValveSoftware/openvr/issues/914
https://github.com/ValveSoftware/openvr/issues/926
https://github.com/ValveSoftware/openvr/issues/879
You can also make it appear by changing the
C:\Program Files (x86)\Steam\config\vrappconfig\*.vrappconfig file for your
project to have a "last_launch_time" of something greater than zero.
From experimentation it seems that there's a cutoff time around 2 weeks before
the current time. Setting it to the day before seems to be a good bet. (In unix
time).
*/
[[noreturn]] void openBindingsMenu()
{
// Prefix the logs with this to visibly document that this isn't how things
// are supposed to be. Hopefully someone reads the logs and comes here after
// Valve has fixed it.
constexpr auto logPrefix = "[HACK]::openBindingsMenu ";
auto initError = vr::VRInitError_None;
LOG( INFO ) << logPrefix << "Initializing application as scene.";
vr::VR_Init( &initError, vr::VRApplication_Scene );
if ( initError != vr::VRInitError_None )
{
LOG( ERROR ) << logPrefix << "Error initializing application as scene.";
exit( 2 );
}
else
{
LOG( INFO ) << logPrefix << "Application initialized as scene.";
}
// This needs to be initialized, otherwise the bindings won't show up in the
// menu.
input::Manifest manifest;
// SteamVR just needs a good enough time to start up comfortably and for the
// user to get into the bindings menu.
while ( true )
{
}
}
OpenVR_Init::OpenVR_Init()
{
initializeProperly();
// The function call and error message was the same for all version checks.
// Specific error messages are unlikely to be necessary since both the type
@@ -70,9 +135,14 @@ OpenVR_Init::OpenVR_Init()
{
reportVersionError( vr::IVRNotifications_Version );
}
else if ( !vr::VR_IsInterfaceVersionValid( vr::IVRInput_Version ) )
{
reportVersionError( vr::IVRInput_Version );
}
}
OpenVR_Init::~OpenVR_Init()
{
vr::VR_Shutdown();
}
} // namespace openvr_init
+5
View File
@@ -1,5 +1,9 @@
#pragma once
namespace openvr_init
{
[[noreturn]] void openBindingsMenu();
/*!
Initializes OpenVR and checks validity of interface versions. Shuts down OpenVR
when destroyed.
@@ -33,3 +37,4 @@ public:
// Move assignment
const OpenVR_Init operator=( OpenVR_Init&& ) = delete;
};
} // namespace openvr_init
+48
View File
@@ -0,0 +1,48 @@
{
"default_bindings": [
{
"controller_type": "vive_controller",
"binding_url": "default_action_manifests/vive_defaults.json"
}
],
"actions": [
{
"name": "/actions/main/in/NextTrack",
"requirement": "optional",
"type": "boolean"
},
{
"name": "/actions/main/in/PreviousTrack",
"requirement": "optional",
"type": "boolean"
},
{
"name": "/actions/main/in/PausePlayTrack",
"requirement": "optional",
"type": "boolean"
},
{
"name": "/actions/main/in/StopTrack",
"requirement": "optional",
"type": "boolean"
}
],
"action_sets": [
{
"name": "/actions/main",
"usage": "leftright"
}
],
"localization" : [
{
"language_tag": "en",
"/actions/main" : "Advanced Settings Actions",
"/actions/main/in/NextTrack" : "Play Next Track",
"/actions/main/in/PreviousTrack" : "Play Previous Track",
"/actions/main/in/PausePlayTrack" : "Pause/Play Track",
"/actions/main/in/StopTrack" : "Stop Track"
}
]
}
+1
View File
@@ -0,0 +1 @@
start AdvancedSettings.exe -bindingsinterface
@@ -0,0 +1,14 @@
{
"alias_info" : {},
"app_key" : "matzman666.advancedsettings",
"bindings" : {
"/actions/main" : {
"sources" : []
}
},
"controller_type" : "vive_controller",
"description" : "Nothing has been bound by default.",
"name" : "Empty Bindings (default)",
"options" : {},
"simulated_actions" : []
}
+14 -5
View File
@@ -42,10 +42,11 @@ MyStackViewPage {
RowLayout {
spacing: 18
Layout.fillWidth: true
MyPushButton {
text: "Keyboard Input"
Layout.preferredWidth: 200
Layout.fillWidth: true
onClicked: {
OverlayController.showKeyboard("", 601)
}
@@ -61,7 +62,7 @@ MyStackViewPage {
MyPushButton {
text: "Enter"
Layout.preferredWidth: 200
Layout.fillWidth: true
onClicked: {
UtilitiesTabController.sendKeyboardEnter()
}
@@ -69,7 +70,7 @@ MyStackViewPage {
MyPushButton {
text: "Alt-Tab"
Layout.preferredWidth: 200
Layout.fillWidth: true
onClicked: {
UtilitiesTabController.sendKeyboardAltTab()
}
@@ -77,7 +78,7 @@ MyStackViewPage {
MyPushButton {
text: "Backspace"
Layout.preferredWidth: 200
Layout.fillWidth: true
onClicked: {
UtilitiesTabController.sendKeyboardBackspace(1)
}
@@ -85,11 +86,19 @@ MyStackViewPage {
MyPushButton {
text: "10x Backspace"
Layout.preferredWidth: 200
Layout.fillWidth: true
onClicked: {
UtilitiesTabController.sendKeyboardBackspace(10)
}
}
MyPushButton {
text: "Alt-Enter"
Layout.fillWidth: true
onClicked: {
UtilitiesTabController.sendKeyboardAltEnter()
}
}
}
}
}
+1
View File
@@ -17,6 +17,7 @@ public:
virtual void sendKeyboardEnter() = 0;
virtual void sendKeyboardBackspace( const int count ) = 0;
virtual void sendKeyboardAltTab() = 0;
virtual void sendKeyboardAltEnter() = 0;
virtual void sendMediaNextSong() = 0;
virtual void sendMediaPreviousSong() = 0;
virtual void sendMediaPausePlay() = 0;
@@ -78,6 +78,11 @@ void UtilitiesTabController::sendKeyboardEnter()
keyboardInput->sendKeyboardEnter();
}
void UtilitiesTabController::sendKeyboardAltEnter()
{
keyboardInput->sendKeyboardAltEnter();
}
void UtilitiesTabController::sendKeyboardAltTab()
{
keyboardInput->sendKeyboardAltTab();
@@ -69,6 +69,7 @@ public slots:
void sendKeyboardInput( QString input );
void sendKeyboardEnter();
void sendKeyboardAltTab();
void sendKeyboardAltEnter();
void sendKeyboardBackspace( const int count );
void sendMediaNextSong();
void sendMediaPreviousSong();
@@ -28,6 +28,11 @@ void KeyboardInputDummy::sendKeyboardAltTab()
// noop
}
void KeyboardInputDummy::sendKeyboardAltEnter()
{
// noop
}
void KeyboardInputDummy::sendMediaNextSong()
{
// noop
@@ -13,6 +13,7 @@ public:
virtual void sendKeyboardEnter() override;
virtual void sendKeyboardBackspace( const int count ) override;
virtual void sendKeyboardAltTab() override;
virtual void sendKeyboardAltEnter() override;
virtual void sendMediaNextSong() override;
virtual void sendMediaPreviousSong() override;
virtual void sendMediaPausePlay() override;
@@ -234,11 +234,13 @@ a music player.
*/
void KeyboardInputWindows::sendKeyboardAltTab()
{
// VK_MENU is Alt.
const auto pressAlt = createInputStruct( VK_MENU, KeyStatus::Down );
const auto pressTab = createInputStruct( VK_TAB, KeyStatus::Down );
const auto releaseAlt = createInputStruct( VK_MENU, KeyStatus::Up );
const auto releaseTab = createInputStruct( VK_TAB, KeyStatus::Up );
constexpr auto altKey = VK_MENU;
constexpr auto tabKey = VK_TAB;
const auto pressAlt = createInputStruct( altKey, KeyStatus::Down );
const auto pressTab = createInputStruct( tabKey, KeyStatus::Down );
const auto releaseAlt = createInputStruct( altKey, KeyStatus::Up );
const auto releaseTab = createInputStruct( tabKey, KeyStatus::Up );
constexpr auto numberOfActions = 4;
@@ -248,6 +250,30 @@ void KeyboardInputWindows::sendKeyboardAltTab()
sendKeyboardInputRaw( numberOfActions, actions );
}
/*!
Sends an Alt + Tab combination to Windows.
Used for toggling full screen on games and various applications that appear on
the desktop.
*/
void KeyboardInputWindows::sendKeyboardAltEnter()
{
constexpr auto altKey = VK_MENU;
constexpr auto enterKey = VK_RETURN;
const auto pressAlt = createInputStruct( altKey, KeyStatus::Down );
const auto pressEnter = createInputStruct( enterKey, KeyStatus::Down );
const auto releaseAlt = createInputStruct( altKey, KeyStatus::Up );
const auto releaseEnter = createInputStruct( enterKey, KeyStatus::Up );
constexpr auto numberOfActions = 4;
INPUT actions[numberOfActions]
= { pressAlt, pressEnter, releaseAlt, releaseEnter };
sendKeyboardInputRaw( numberOfActions, actions );
}
/*!
Sends a media key Next Song button to Windows.
*/
@@ -13,6 +13,7 @@ public:
virtual void sendKeyboardEnter() override;
virtual void sendKeyboardBackspace( const int count ) override;
virtual void sendKeyboardAltTab() override;
virtual void sendKeyboardAltEnter() override;
virtual void sendMediaNextSong() override;
virtual void sendMediaPreviousSong() override;
virtual void sendMediaPausePlay() override;