diff --git a/Dotnet/AppApi/GameHandler.cs b/Dotnet/AppApi/GameHandler.cs index fd51dcac..2cad61bb 100644 --- a/Dotnet/AppApi/GameHandler.cs +++ b/Dotnet/AppApi/GameHandler.cs @@ -34,9 +34,11 @@ namespace VRCX isSteamVRRunning = true; } + var isHmdAfk = VRCXVR.Instance.IsHmdAfk; + // TODO: fix this throwing an exception for being called before the browser is ready. somehow it gets past the checks if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame) - MainForm.Instance.Browser.ExecuteScriptAsync("$app.updateIsGameRunning", isGameRunning, isSteamVRRunning); + MainForm.Instance.Browser.ExecuteScriptAsync("$app.updateIsGameRunning", isGameRunning, isSteamVRRunning, isHmdAfk); } /// diff --git a/Dotnet/Overlay/VRCXVR.cs b/Dotnet/Overlay/VRCXVR.cs index 53c6b0dd..7aaccf51 100644 --- a/Dotnet/Overlay/VRCXVR.cs +++ b/Dotnet/Overlay/VRCXVR.cs @@ -42,6 +42,7 @@ namespace VRCX private Texture2D _texture2; private Thread _thread; private bool _wristOverlayActive; + public bool IsHmdAfk { get; private set; } static VRCXVR() { @@ -190,6 +191,7 @@ namespace VRCX if (type == EVREventType.VREvent_Quit) { active = false; + IsHmdAfk = false; OpenVR.Shutdown(); nextInit = DateTime.UtcNow.AddSeconds(10); system = null; @@ -247,6 +249,7 @@ namespace VRCX else if (active) { active = false; + IsHmdAfk = false; OpenVR.Shutdown(); _deviceListLock.EnterWriteLock(); try @@ -314,102 +317,120 @@ namespace VRCX for (var i = 0u; i < OpenVR.k_unMaxTrackedDeviceCount; ++i) { var devClass = system.GetTrackedDeviceClass(i); - if (devClass == ETrackedDeviceClass.Controller || - devClass == ETrackedDeviceClass.GenericTracker || - devClass == ETrackedDeviceClass.TrackingReference) + switch (devClass) { - var err = ETrackedPropertyError.TrackedProp_Success; - var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err); - if (err != ETrackedPropertyError.TrackedProp_Success) - { - batteryPercentage = 1f; - } - - err = ETrackedPropertyError.TrackedProp_Success; - var isCharging = system.GetBoolTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceIsCharging_Bool, ref err); - if (err != ETrackedPropertyError.TrackedProp_Success) - { - isCharging = false; - } - - sb.Clear(); - system.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_TrackingSystemName_String, sb, (uint)sb.Capacity, ref err); - var isOculus = sb.ToString().IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0; - // Oculus : B/Y, Bit 1, Mask 2 - // Oculus : A/X, Bit 7, Mask 128 - // Vive : Menu, Bit 1, Mask 2, - // Vive : Grip, Bit 2, Mask 4 - var role = system.GetControllerRoleForTrackedDeviceIndex(i); - if (role == ETrackedControllerRole.LeftHand || role == ETrackedControllerRole.RightHand) - { - if (_overlayHand == 0 || - (_overlayHand == 1 && role == ETrackedControllerRole.LeftHand) || - (_overlayHand == 2 && role == ETrackedControllerRole.RightHand)) + case ETrackedDeviceClass.HMD: + var success = system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)); + if (!success) + break; // this fails while SteamVR overlay is open + + var prox = state.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_ProximitySensor)); + var isHmdAfk = prox == 0; + if (isHmdAfk != IsHmdAfk) { - if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) && - (state.ulButtonPressed & (_menuButton ? 2u : isOculus ? 128u : 4u)) != 0) - { - if (role == ETrackedControllerRole.LeftHand) - { - Array.Copy(_translationLeft, _translation, 3); - Array.Copy(_rotationLeft, _rotation, 3); - } - else - { - Array.Copy(_translationRight, _translation, 3); - Array.Copy(_rotationRight, _rotation, 3); - } + IsHmdAfk = isHmdAfk; + AppApi.Instance.CheckGameRunning(); + } + break; + case ETrackedDeviceClass.Controller: + case ETrackedDeviceClass.GenericTracker: + case ETrackedDeviceClass.TrackingReference: + { + var err = ETrackedPropertyError.TrackedProp_Success; + var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err); + if (err != ETrackedPropertyError.TrackedProp_Success) + { + batteryPercentage = 1f; + } - overlayIndex = i; + err = ETrackedPropertyError.TrackedProp_Success; + var isCharging = system.GetBoolTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceIsCharging_Bool, ref err); + if (err != ETrackedPropertyError.TrackedProp_Success) + { + isCharging = false; + } + + sb.Clear(); + system.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_TrackingSystemName_String, sb, (uint)sb.Capacity, ref err); + var isOculus = sb.ToString().IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0; + // Oculus : B/Y, Bit 1, Mask 2 + // Oculus : A/X, Bit 7, Mask 128 + // Vive : Menu, Bit 1, Mask 2, + // Vive : Grip, Bit 2, Mask 4 + var role = system.GetControllerRoleForTrackedDeviceIndex(i); + if (role == ETrackedControllerRole.LeftHand || role == ETrackedControllerRole.RightHand) + { + if (_overlayHand == 0 || + (_overlayHand == 1 && role == ETrackedControllerRole.LeftHand) || + (_overlayHand == 2 && role == ETrackedControllerRole.RightHand)) + { + if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) && + (state.ulButtonPressed & (_menuButton ? 2u : isOculus ? 128u : 4u)) != 0) + { + if (role == ETrackedControllerRole.LeftHand) + { + Array.Copy(_translationLeft, _translation, 3); + Array.Copy(_rotationLeft, _rotation, 3); + } + else + { + Array.Copy(_translationRight, _translation, 3); + Array.Copy(_rotationRight, _rotation, 3); + } + + overlayIndex = i; + } } } - } - var type = string.Empty; - if (devClass == ETrackedDeviceClass.Controller) - { - if (role == ETrackedControllerRole.LeftHand) + var type = string.Empty; + if (devClass == ETrackedDeviceClass.Controller) { - type = "leftController"; + if (role == ETrackedControllerRole.LeftHand) + { + type = "leftController"; + } + else if (role == ETrackedControllerRole.RightHand) + { + type = "rightController"; + } + else + { + type = "controller"; + } } - else if (role == ETrackedControllerRole.RightHand) + else if (devClass == ETrackedDeviceClass.GenericTracker) { - type = "rightController"; + type = "tracker"; } - else + else if (devClass == ETrackedDeviceClass.TrackingReference) { - type = "controller"; + type = "base"; } - } - else if (devClass == ETrackedDeviceClass.GenericTracker) - { - type = "tracker"; - } - else if (devClass == ETrackedDeviceClass.TrackingReference) - { - type = "base"; - } - var item = new[] - { - type, - system.IsTrackedDeviceConnected(i) - ? "connected" - : "disconnected", - isCharging - ? "charging" - : "discharging", - (batteryPercentage * 100).ToString(), - poses[i].eTrackingResult.ToString() - }; - _deviceListLock.EnterWriteLock(); - try - { - _deviceList.Add(item); - } - finally - { - _deviceListLock.ExitWriteLock(); + var item = new[] + { + type, + system.IsTrackedDeviceConnected(i) + ? "connected" + : "disconnected", + isCharging + ? "charging" + : "discharging", + (batteryPercentage * 100).ToString(), + poses[i].eTrackingResult.ToString() + }; + _deviceListLock.EnterWriteLock(); + try + { + _deviceList.Add(item); + } + finally + { + _deviceListLock.ExitWriteLock(); + } + + break; } } } diff --git a/html/src/app.js b/html/src/app.js index 8f3cb1e2..e03b54cf 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -5231,6 +5231,7 @@ speechSynthesis.getVoices(); isGameRunning: false, isGameNoVR: configRepository.getBool('isGameNoVR'), isSteamVRRunning: false, + isHmdAfk: false, appVersion: '', latestAppVersion: '', ossDialog: false @@ -5455,7 +5456,8 @@ speechSynthesis.getVoices(); $app.methods.updateIsGameRunning = function ( isGameRunning, - isSteamVRRunning + isSteamVRRunning, + isHmdAfk ) { if (isGameRunning !== this.isGameRunning) { this.isGameRunning = isGameRunning; @@ -5485,6 +5487,10 @@ speechSynthesis.getVoices(); this.isSteamVRRunning = isSteamVRRunning; console.log('isSteamVRRunning:', isSteamVRRunning); } + if (isHmdAfk !== this.isHmdAfk) { + this.isHmdAfk = isHmdAfk; + console.log('isHmdAfk:', isHmdAfk); + } this.updateOpenVR(); }; @@ -6227,8 +6233,13 @@ speechSynthesis.getVoices(); (this.desktopToast === 'Game Running' && this.isGameRunning) || (this.desktopToast === 'Desktop Mode' && this.isGameNoVR && - this.isGameRunning) + this.isGameRunning) || + (this.afkDesktopToast && + this.isHmdAfk && + this.isGameRunning && + !this.isGameNoVR) ) { + // this if statement looks like it has seen better days playDesktopToast = true; } var playXSNotification = this.xsNotifications; @@ -14212,6 +14223,10 @@ speechSynthesis.getVoices(); 'VRCX_desktopToast', 'Never' ); + $app.data.afkDesktopToast = configRepository.getBool( + 'VRCX_afkDesktopToast', + false + ); $app.data.minimalFeed = configRepository.getBool('VRCX_minimalFeed', false); $app.data.displayVRCPlusIconsAsAvatar = configRepository.getBool( 'displayVRCPlusIconsAsAvatar', @@ -14366,6 +14381,7 @@ speechSynthesis.getVoices(); this.imageNotifications ); configRepository.setString('VRCX_desktopToast', this.desktopToast); + configRepository.setBool('VRCX_afkDesktopToast', this.afkDesktopToast); configRepository.setBool('VRCX_minimalFeed', this.minimalFeed); configRepository.setBool( 'displayVRCPlusIconsAsAvatar', diff --git a/html/src/localization/en/en.json b/html/src/localization/en/en.json index 8ab7e790..be70dd82 100644 --- a/html/src/localization/en/en.json +++ b/html/src/localization/en/en.json @@ -322,7 +322,8 @@ "when_to_display_outside_vr": "Outside VR", "when_to_display_game_closed": "Game Closed", "when_to_display_game_running": "Game Running", - "when_to_display_always": "Always" + "when_to_display_always": "Always", + "desktop_notification_while_afk": "Desktop Notification While AFK" }, "text_to_speech": { "header": "Text-To-Speech Options", diff --git a/html/src/mixins/tabs/settings.pug b/html/src/mixins/tabs/settings.pug index e4fbcaca..120a42e8 100644 --- a/html/src/mixins/tabs/settings.pug +++ b/html/src/mixins/tabs/settings.pug @@ -273,6 +273,9 @@ mixin settingsTab() el-radio-button(label="Game Closed") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_game_closed') }} el-radio-button(label="Game Running") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_game_running') }} el-radio-button(label="Always") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_always') }} + div.options-container-item + span.name(style="min-width:225px") {{ $t('view.settings.notifications.notifications.desktop_notifications.desktop_notification_while_afk') }} + el-switch(v-model="afkDesktopToast" @change="saveOpenVROption") //- Notifications | Notifications | Text-to-Speech Options div.options-container span.sub-header {{ $t('view.settings.notifications.notifications.text_to_speech.header') }} diff --git a/html/src/vr.pug b/html/src/vr.pug index 34b1662f..d8f81c71 100644 --- a/html/src/vr.pug +++ b/html/src/vr.pug @@ -462,12 +462,6 @@ html img(v-if="device[1] !== 'connected'" src="images/base_status_off.png") img(v-else src="images/base_status_ready.png") span(v-if="device[3] !== 100") {{ device[3] }}x - div(v-else class="tracker-device" :class="trackingResultToClass(device[4])") - img(v-if="device[1] !== 'connected'" src="images/other_status_off.png") - img(v-else-if="device[2] === 'charging'" src="images/other_status_ready_charging.png") - img(v-else-if="device[3] < 20" src="images/other_status_ready_low.png") - img(v-else src="images/other_status_ready.png") - span {{ device[3] }}% .x-containerbottom template(v-if="nowPlaying.playing") span(style="float:right;padding-left:10px") {{ nowPlaying.remainingText }}