Add an optional pop-up notification when auto-turn is toggled (#496)

* Implement (most of) pop-up notification when autoturn is enabled

* Add neato fading: doesn't appear to impact performance

* formatting

* added macro and UI for notification of auto-turn

* changed notification default to true for auto-turn

* added common issue for trackers

* added warning for custom keys

* minor documentation markdown format fixes

* fix qml syntax error in atgb

* gasd

Co-authored-by: ykeara <ykeara1@gmail.com>
This commit is contained in:
Chelsea Jaggi
2020-08-11 20:03:35 -05:00
committed by GitHub
co-authored by ykeara
parent 90d980dcab
commit 6d1953070a
13 changed files with 324 additions and 32 deletions
+10 -2
View File
@@ -125,7 +125,7 @@ Detailed instructions are available [here](docs/building_for_linux.md).
### Overall Feature Overview Guides
- [Kung's 3.0 New Feature Guide (video/youtube)[https://youtu.be/2ZHdjOfnqOU)]
- [Kung's 3.0 New Feature Guide (video/youtube)[https://youtu.be/2ZHdjOfnqOU]
### SteamVR Input System (keybinds for app)
@@ -472,7 +472,7 @@ Allows users to temporarily move and rotate the center of the playspace. This al
- **Brightness**: Same as regular.
- **Opacity**: Adjusts opacity of color overlay.
- **Toggle On/Off**: Turns on/off Color Adjustment Overlay.
- **<Color>**: Adjusts the overlay to adjust the color.
- **Color (Red/Green/Blue)**: Adjusts the overlay to adjust the color.
## - Utilities Page
@@ -546,6 +546,14 @@ Full build instructions can be found [here](docs/building_for_linux.md).
- **Cause:** WMR boundary off, or set up for standing only.
- **Solution:** Please set-up WMR for all experiences, and then if you don't want WMR boundary you can toggle off the boundary **after** SteamVR/OpenVR has been started.
- **Issue:** While using Trackers (additional devices besides controllers) Keybinds don't work.
- **Cause:** Trackers can Assume controller roles, and prevent your controllers from working properly.
- **Solution:** Assign Tracker Roles Via SteamVR Widget to anything besides `held-in-hand`
- **Issue:** Custom Key Presses Not Saving In file.
- **Cause:** Key Presses Modified while Advanced Settings is running.
- **Solution:** Only modify the settings file while VR/Advanced Settings is **not** running.
# License
This software is released under GPL 3.0, and other third-party Licenses
+5 -1
View File
@@ -118,6 +118,10 @@
### Case Sensative
- basic characters are all LOWER case, while keys such as ENTER are all UPPER case.
### Custom Keys Not Saving.
- We only load keybinds from file on start-up, and save based on what is in memory (not in file)
- **ONLY** edit the settings file while Advanced Settings is **not** running.
### Focus Issues
- we deliver the keypress to the OS, depending on your set-up and program you may have to have the window "in-focus"
@@ -126,4 +130,4 @@
- alt + tab, alt + F4 = `*TAB *F4`
## Parser Spec
(Parser Spec)[https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/blob/master/docs/specs/Keyboard_Manager-Parser_Spec.md]
[Parser Spec](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/blob/master/docs/specs/Keyboard_Manager-Parser_Spec.md)
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg8">
<defs
id="defs2">
<rect
x="43.277892"
y="36.927076"
width="23.295368"
height="30.546571"
id="rect1983" />
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;">
<path
id="path1440"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#ffffff;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path1437"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#ffffff;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<rect
y="17.717316"
x="17.717316"
height="64.565376"
width="64.565376"
id="rect1404"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:5.0000958;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="72.682518"
x="26.972013"
height="0.34497312"
width="46.055973"
id="rect1406"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.65502977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
transform="rotate(-90)"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4.61399984;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1406-3"
width="40.386425"
height="0.38642606"
x="-69.420227"
y="72.641556" />
<g
transform="matrix(2.1165483,0,0,2.1165483,-81.187201,-75.769488)"
id="g4567">
<path
style="fill:none;stroke:#ffffff;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2.50000007, 2.50000007;stroke-dashoffset:17;stroke-opacity:1"
d="m 72.479209,53.094746 c 0,0 -6.460096,-1.327245 -12.308933,4.1861 -5.848839,5.513348 -5.595517,8.406487 -5.595517,8.406487"
id="path1435" />
<path
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:17;stroke-opacity:1"
id="path1977"
d="m 53.243307,65.791321 0.299848,-4.141501 3.436721,2.330426 z" />
</g>
<path
d="m 72.968407,24.57116 3.522289,6.100784 h -7.044579 z"
id="path1979"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:64.2519989;stroke-opacity:1" />
<text
y="-87.638542"
x="-96.653877"
transform="scale(0.9999973,1.0000027)"
style="font-style:normal;font-weight:normal;font-size:44.66781998px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1983);fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.81372094"
id="text1981"
xml:space="preserve"><tspan
style="stroke-width:2.81372094"
x="25.116493"
y="55.786346"
id="tspan17"><tspan
style="font-size:44.66781998px;fill:#ffffff;fill-opacity:1;stroke-width:2.81372094"
id="tspan15">A</tspan></tspan></text>
<ellipse
ry="32.294323"
rx="32.294319"
cy="49.999966"
cx="50.000027"
id="path4571"
style="fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:4.9769268;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path4573"
d="M 28.177966,24.682203 76.165254,69.385592"
style="fill:none;stroke:#ff0000;stroke-width:5.0000958;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -35,10 +35,18 @@ GroupBox {
MyToggleButton {
id: autoTurn
text: "Toggle On/Off"
Layout.preferredWidth: 300
Layout.preferredWidth: 250
onCheckedChanged: {
RotationTabController.setAutoTurnEnabled(this.checked, true); }
}
MyToggleButton {
id: autoTurnNotificationToggle
text: "HMD Icon"
Layout.preferredWidth: 175
onCheckedChanged: {
RotationTabController.setAutoTurnShowNotification(this.checked, true)
}
}
MyText {
text: "Activation Dist:"
@@ -160,7 +168,7 @@ GroupBox {
}
MyText {
text: "Turn Speed (deg/sec):"
text: "Turn Speed(deg/sec):"
horizontalAlignment: Text.AlignRight
Layout.rightMargin: 10
}
@@ -174,7 +182,7 @@ GroupBox {
Layout.fillWidth: true
onPositionChanged: {
var val = this.value
speedValueText.text = val.toFixed()
speedValueText.text = val.toFixed()+ "°"
}
onValueChanged: {
@@ -184,7 +192,7 @@ GroupBox {
MyTextField {
id: speedValueText
text: "90"
text: "90°"
keyBoardUID: 1003
Layout.preferredWidth: 100
Layout.leftMargin: 10
@@ -203,29 +211,30 @@ GroupBox {
speedSlider.value = val;
}
//converts the centidegrees to degrees
text = (((RotationTabController.autoTurnSpeed)/100).toFixed());
text = (((RotationTabController.autoTurnSpeed)/100).toFixed()) + "°";
}
}
}
RowLayout{
MyText{
text: "Detangle Angle: "
horizontalAlignment: Text.AlignLeft
Layout.preferredWidth: 250
Layout.preferredWidth: 200
Layout.rightMargin: 5
}
MyText{
text:"Min Rotations(deg):"
text:"Min Rotations:"
Layout.rightMargin: 5
}
MyTextField {
id: detangleAngleStartText
text: "360"
text: "360°"
keyBoardUID: 1005
Layout.preferredWidth: 100
Layout.leftMargin: 5
@@ -239,6 +248,7 @@ GroupBox {
val = 3600
}
RotationTabController.setMinCordTangle((val*(Math.PI/180)), true);
text = (Math.round(val).toFixed())+ "°";
}
}
}
@@ -247,7 +257,7 @@ GroupBox {
}
MyText{
text: "Max Wall Angle(deg): "
text: "Max Wall Angle: "
horizontalAlignment: Text.AlignRight
Layout.rightMargin: 10
Layout.fillWidth: true
@@ -255,7 +265,7 @@ GroupBox {
}
MyTextField {
id: detangleAngleAssistText
text: "10"
text: "10°"
keyBoardUID: 1006
Layout.preferredWidth: 100
Layout.leftMargin: 10
@@ -269,6 +279,7 @@ GroupBox {
val = 3600
}
RotationTabController.setCordDetangleAngle((val*(Math.PI/180)), true);
text = (Math.round(val).toFixed())+ "°";
}
}
}
@@ -285,6 +296,7 @@ GroupBox {
deactivationSlider.value = RotationTabController.autoTurnDeactivationDistance.toFixed(2)
cornerAngle.checked = RotationTabController.autoTurnUseCornerAngle
speedSlider.value = (RotationTabController.autoTurnSpeed/100).toFixed()
autoTurnNotificationToggle.checked = RotationTabController.autoTurnShowNotification
if(RotationTabController.autoTurnMode === 1){
autoTurnModeToggle.checked = true;
@@ -293,8 +305,8 @@ GroupBox {
autoTurnModeToggle.checked = false;
}
detangleAngleStartText.text = parseInt(RotationTabController.minCordTangle*(180/Math.PI))
detangleAngleAssistText.text = parseInt(RotationTabController.cordDetangleAngle*(180/Math.PI))
detangleAngleStartText.text = parseInt(RotationTabController.minCordTangle*(180/Math.PI))+ "°"
detangleAngleAssistText.text = parseInt(RotationTabController.cordDetangleAngle*(180/Math.PI))+ "°"
}
Connections {
@@ -327,10 +339,13 @@ GroupBox {
}
}
onMinCordTangleChanged:{
detangleAngleStartText.text = parseInt(RotationTabController.minCordTangle*(180/Math.PI))
detangleAngleStartText.text = parseInt(RotationTabController.minCordTangle*(180/Math.PI))+ "°"
}
onCordDetangleAngleChanged:{
detangleAngleAssistText.text = parseInt(RotationTabController.cordDetangleAngle*(180/Math.PI))
detangleAngleAssistText.text = parseInt(RotationTabController.cordDetangleAngle*(180/Math.PI))+ "°"
}
onAutoTurnShowNotificationChanged:{
autoTurnNotificationToggle.checked = RotationTabController.autoTurnShowNotification
}
}
}
@@ -393,6 +393,10 @@ private:
SettingCategory::Rotation,
QtInfo{ "autoturnVestibularMotionEnabled" },
false },
BoolSettingValue{ BoolSetting::ROTATION_autoturnShowNotification,
SettingCategory::Rotation,
QtInfo{ "autoturnShowNotification" },
true }
};
constexpr static auto doubleSettingSize
+2 -1
View File
@@ -55,8 +55,9 @@ enum class BoolSetting
ROTATION_autoturnEnabled,
ROTATION_autoturnUseCornerAngle,
ROTATION_autoturnVestibularMotionEnabled,
ROTATION_autoturnShowNotification,
// LAST_ENUMERATOR must always be set to the last value
LAST_ENUMERATOR = ROTATION_autoturnVestibularMotionEnabled,
LAST_ENUMERATOR = ROTATION_autoturnShowNotification,
};
enum class DoubleSetting
+2 -14
View File
@@ -63,18 +63,6 @@ void AudioTabController::initStage1()
eventLoopTick();
}
std::optional<std::string> verifyIconFilePath( std::string filename )
{
const auto notifIconPath = paths::binaryDirectoryFindFile( filename );
if ( !notifIconPath.has_value() )
{
LOG( ERROR ) << "Could not find push to talk icon \"" << filename
<< "\"";
}
return notifIconPath;
}
void AudioTabController::initStage2()
{
const auto pushToTalkOverlayKey
@@ -102,9 +90,9 @@ void AudioTabController::initStage2()
= "/res/img/audio/microphone/ptm_notification.png";
const auto pushToTalkIconFilePath
= verifyIconFilePath( pushToTalkIconFilepath );
= paths::verifyIconFilePath( pushToTalkIconFilepath );
const auto pushToMuteIconFilePath
= verifyIconFilePath( pushToMuteIconFilepath );
= paths::verifyIconFilePath( pushToMuteIconFilepath );
if ( !pushToTalkIconFilePath.has_value()
|| !pushToMuteIconFilePath.has_value() )
@@ -17,6 +17,60 @@ void RotationTabController::initStage1()
void RotationTabController::initStage2( OverlayController* var_parent )
{
const auto autoturnOverlayKey
= std::string( application_strings::applicationKey )
+ ".autoturnnotification";
const auto overlayError
= vr::VROverlay()->CreateOverlay( autoturnOverlayKey.c_str(),
autoturnOverlayKey.c_str(),
&m_autoturnValues.overlayHandle );
if ( overlayError != vr::VROverlayError_None )
{
LOG( ERROR ) << "Could not create autoturn notification overlay: "
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
overlayError );
emit defaultProfileDisplay();
return;
}
constexpr auto autoturnIconFilepath = "/res/img/rotation/autoturn.png";
constexpr auto noautoturnIconFilepath = "/res/img/rotation/noautoturn.png";
const auto autoturnIconFilePath
= paths::verifyIconFilePath( autoturnIconFilepath );
const auto noautoturnIconFilePath
= paths::verifyIconFilePath( noautoturnIconFilepath );
if ( !autoturnIconFilePath.has_value()
|| !noautoturnIconFilePath.has_value() )
{
emit defaultProfileDisplay();
return;
}
m_autoturnValues.autoturnPath = *autoturnIconFilePath;
m_autoturnValues.noautoturnPath = *noautoturnIconFilePath;
auto pushToPath = m_autoturnValues.autoturnPath.c_str();
vr::VROverlay()->SetOverlayFromFile( m_autoturnValues.overlayHandle,
pushToPath );
vr::VROverlay()->SetOverlayWidthInMeters( m_autoturnValues.overlayHandle,
0.02f );
vr::HmdMatrix34_t notificationTransform
= { { { 1.0f, 0.0f, 0.0f, 0.12f },
{ 0.0f, 1.0f, 0.0f, 0.08f },
{ 0.0f, 0.0f, 1.0f, -0.3f } } };
vr::VROverlay()->SetOverlayTransformTrackedDeviceRelative(
m_autoturnValues.overlayHandle,
vr::k_unTrackedDeviceIndex_Hmd,
&notificationTransform );
emit defaultProfileDisplay();
this->parent = var_parent;
}
@@ -65,6 +119,29 @@ void RotationTabController::eventLoopTick(
m_autoTurnChaperoneDistancesLast = std::move( chaperoneDistances );
}
}
if ( m_autoTurnNotificationTimestamp )
{
auto count = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now()
- *m_autoTurnNotificationTimestamp )
.count();
if ( count > 1500 )
{
m_autoTurnNotificationTimestamp.reset();
if ( getNotificationOverlayHandle()
!= vr::k_ulOverlayHandleInvalid )
{
vr::VROverlay()->HideOverlay( getNotificationOverlayHandle() );
}
}
else
{
float pct
= std::min( 1.0f, 3.0f - static_cast<float>( count ) / 500.0f );
vr::VROverlay()->SetOverlayAlpha( getNotificationOverlayHandle(),
pct );
}
}
}
void RotationTabController::doVestibularMotion(
@@ -453,6 +530,12 @@ bool RotationTabController::autoTurnUseCornerAngle() const
settings::BoolSetting::ROTATION_autoturnUseCornerAngle );
}
bool RotationTabController::autoTurnShowNotification() const
{
return settings::getSetting(
settings::BoolSetting::ROTATION_autoturnShowNotification );
}
double RotationTabController::cordDetangleAngle() const
{
return settings::getSetting(
@@ -505,6 +588,39 @@ void RotationTabController::setAutoTurnEnabled( bool value, bool notify )
{
emit autoTurnEnabledChanged( value );
}
if ( !value )
{
vr::VROverlay()->SetOverlayFromFile(
m_autoturnValues.overlayHandle,
m_autoturnValues.noautoturnPath.c_str() );
}
else
{
vr::VROverlay()->SetOverlayFromFile(
m_autoturnValues.overlayHandle,
m_autoturnValues.autoturnPath.c_str() );
}
if ( autoTurnShowNotification()
&& getNotificationOverlayHandle() != vr::k_ulOverlayHandleInvalid )
{
vr::VROverlay()->SetOverlayAlpha( getNotificationOverlayHandle(),
1.0f );
vr::VROverlay()->ShowOverlay( getNotificationOverlayHandle() );
m_autoTurnNotificationTimestamp.emplace(
std::chrono::steady_clock::now() );
}
}
void RotationTabController::setAutoTurnShowNotification( bool value,
bool notify )
{
settings::setSetting(
settings::BoolSetting::ROTATION_autoturnShowNotification, value );
if ( notify )
{
emit autoTurnShowNotificationChanged( value );
}
}
void RotationTabController::setAutoTurnActivationDistance( float value,
bool notify )
@@ -6,6 +6,7 @@
#include <thread>
#include <openvr.h>
#include <cmath>
#include <optional>
#include "../utils/FrameRateUtils.h"
#include "../utils/ChaperoneUtils.h"
#include "../settings/settings_object.h"
@@ -82,10 +83,25 @@ class RotationTabController : public QObject
Q_PROPERTY(
double vestibularMotionRadius READ vestibularMotionRadius WRITE
setVestibularMotionRadius NOTIFY vestibularMotionRadiusChanged )
Q_PROPERTY(
bool autoTurnShowNotification READ autoTurnShowNotification WRITE
setAutoTurnShowNotification NOTIFY autoTurnShowNotificationChanged )
private:
OverlayController* parent;
struct
{
vr::VROverlayHandle_t overlayHandle = vr::k_ulOverlayHandleInvalid;
std::string autoturnPath;
std::string noautoturnPath;
} m_autoturnValues;
virtual vr::VROverlayHandle_t getNotificationOverlayHandle()
{
return m_autoturnValues.overlayHandle;
}
// Variables
int m_autoTurnLinearSmoothTurnRemaining = 0;
std::chrono::steady_clock::time_point m_autoTurnLastUpdate;
@@ -95,6 +111,9 @@ private:
double m_autoTurnRoundingError = 0.0;
std::chrono::steady_clock::time_point::duration m_estimatedFrameRate;
std::optional<std::chrono::steady_clock::time_point>
m_autoTurnNotificationTimestamp;
bool m_isHMDActive = false;
void doAutoTurn(
@@ -116,6 +135,7 @@ public:
float autoTurnActivationDistance() const;
float autoTurnDeactivationDistance() const;
bool autoTurnUseCornerAngle() const;
bool autoTurnShowNotification() const;
double cordDetangleAngle() const;
double minCordTangle() const;
int autoTurnSpeed() const;
@@ -126,6 +146,7 @@ public:
public slots:
void setAutoTurnEnabled( bool value, bool notify = true );
void setAutoTurnShowNotification( bool value, bool notify = true );
void setAutoTurnActivationDistance( float value, bool notify = true );
void setAutoTurnDeactivationDistance( float value, bool notify = true );
void setAutoTurnUseCornerAngle( bool value, bool notify = true );
@@ -138,7 +159,9 @@ public slots:
signals:
void defaultProfileDisplay();
void autoTurnEnabledChanged( bool value );
void autoTurnShowNotificationChanged( bool value );
void autoTurnActivationDistanceChanged( float value );
void autoTurnDeactivationDistanceChanged( float value );
void autoTurnUseCornerAngleChanged( bool value );
+11
View File
@@ -57,4 +57,15 @@ optional<string> settingsDirectory()
return path.toStdString();
}
std::optional<std::string> verifyIconFilePath( std::string filename )
{
const auto notifIconPath = paths::binaryDirectoryFindFile( filename );
if ( !notifIconPath.has_value() )
{
LOG( ERROR ) << "Could not find icon \"" << filename << "\"";
}
return notifIconPath;
}
} // namespace paths
+2
View File
@@ -12,4 +12,6 @@ optional<string> binaryDirectoryFindFile( string fileName );
optional<string> settingsDirectory();
std::optional<std::string> verifyIconFilePath( std::string filename );
} // namespace paths