From 7226c724d7974812e699e77ae418c1aa6308ff48 Mon Sep 17 00:00:00 2001 From: jrhodnik Date: Sun, 2 Jun 2019 16:54:01 -0400 Subject: [PATCH] Generalized overlay locations. Added controller as a location, and made GUI to configure it. Fixed "Hide overlay when window not found" functionality. Added scrolling for WindowOverlay and MonitorOverlay. --- VRDash/Logger.cs | 17 +++++ VRDash/MainWindow.xaml | 2 +- .../OverlayLocation/ControllerLocation.cs | 10 +-- VRDash/Overlay/MonitorOverlay.cs | 17 +++-- VRDash/Overlay/WindowOverlay.cs | 57 +++++++++------- VRDash/UI/CreateNewOverlay.xaml | 2 +- .../ControllerLocationEditor.xaml | 67 +++++++++++++++---- .../ControllerLocationEditor.xaml.cs | 63 +++++++++++++++++ VRDash/UI/OverlayEditor.xaml | 10 ++- VRDash/WindowSelectors/FromProcessName.cs | 35 +++++++--- VRDash/WindowSelectors/FromWindowTitle.cs | 26 ++++--- 11 files changed, 237 insertions(+), 69 deletions(-) diff --git a/VRDash/Logger.cs b/VRDash/Logger.cs index 3d42ca6..4888d3d 100644 --- a/VRDash/Logger.cs +++ b/VRDash/Logger.cs @@ -8,6 +8,8 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using VRDash.Overlay; +using VRDash.Overlay.Config; namespace VRDash { @@ -82,7 +84,22 @@ namespace VRDash { public static ILog GetLogger(this object instance) { + if (typeof(IOverlay).IsAssignableFrom(instance.GetType())) + { + IOverlay overlay = (IOverlay)instance; + return GetLogger(instance, overlay); + } return LogManager.GetLogger(instance.GetType()); } + + public static ILog GetLogger(this object instance, IOverlay overlay) + { + return LogManager.GetLogger($"{instance.GetType()} [{overlay.OverlayConfig.Name}]"); + } + + public static ILog GetLogger(this object instance, IOverlayConfig overlayConfig) + { + return LogManager.GetLogger($"{instance.GetType()} [{overlayConfig.Name}]"); + } } } diff --git a/VRDash/MainWindow.xaml b/VRDash/MainWindow.xaml index 17d9dd7..d3da8d0 100644 --- a/VRDash/MainWindow.xaml +++ b/VRDash/MainWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:VRDash" mc:Ignorable="d" - Title="MainWindow" Height="450" Width="800"> + Title="VRDash" Height="700" Width="800"> diff --git a/VRDash/Overlay/Config/OverlayLocation/ControllerLocation.cs b/VRDash/Overlay/Config/OverlayLocation/ControllerLocation.cs index 0348542..83c803e 100644 --- a/VRDash/Overlay/Config/OverlayLocation/ControllerLocation.cs +++ b/VRDash/Overlay/Config/OverlayLocation/ControllerLocation.cs @@ -14,7 +14,7 @@ namespace VRDash.Overlay.Config.OverlayLocation [OverlayLocationInfo("Controller", typeof(ControllerLocationEditor))] public class ControllerLocation : IOverlayLocation { - public ControllerHand Controller { get; private set; } = ControllerHand.Left; + public ControllerHand Controller { get; set; } = ControllerHand.Left; [JsonIgnore] public Matrix3x4 Location { get; private set; } = new Matrix3x4(new Vector4(1, 0, 0, 0), @@ -76,7 +76,7 @@ namespace VRDash.Overlay.Config.OverlayLocation //Location = Matrix3x4.Add(Matrix3x4.CreateFromQuaternion(quat), Location); //Location = Matrix3x4.Add(Matrix3x4.CreateScale(ScaleX, ScaleY, ScaleZ), Location); - + if (m_Overlay.OverlayHandle == OpenVR.k_ulOverlayHandleInvalid || m_ControllerIndex == OpenVR.k_unTrackedDeviceIndexInvalid) { return; } //Index changed, need to update the overlay if (controllerIndex != m_ControllerIndex) @@ -89,11 +89,11 @@ namespace VRDash.Overlay.Config.OverlayLocation if (err != EVROverlayError.None) { - this.GetLogger().Warn($"[{m_Overlay.OverlayConfig.Name}] Error setting tracked device relative to {Controller} hand: {err}"); + this.GetLogger(m_Overlay).Warn($"Error setting tracked device relative to {Controller} hand: {err}"); } else { - this.GetLogger().Info($"[{m_Overlay.OverlayConfig.Name}] Controller index updated."); + this.GetLogger(m_Overlay).Info($"Controller index updated."); } } else @@ -105,7 +105,7 @@ namespace VRDash.Overlay.Config.OverlayLocation if (err != EVROverlayError.None) { - this.GetLogger().Warn($"[{m_Overlay.OverlayConfig.Name}] Error setting tracked device relative to {Controller} hand: {err}"); + this.GetLogger(m_Overlay).Warn($"Error updating tracked device relative to {Controller} hand: {err}"); } } diff --git a/VRDash/Overlay/MonitorOverlay.cs b/VRDash/Overlay/MonitorOverlay.cs index a4ad782..8b1096a 100644 --- a/VRDash/Overlay/MonitorOverlay.cs +++ b/VRDash/Overlay/MonitorOverlay.cs @@ -128,6 +128,8 @@ namespace VRDash.Overlay m_OverlayHandle = overlayHandles.OverlayHandle; m_ThumbnailIcon = overlayHandles.ThumbnailHandle; + overlay.SetOverlayFlag(m_OverlayHandle, VROverlayFlags.SendVRDiscreteScrollEvents, true); + var tempError = OpenVR.Overlay.ShowOverlay(m_OverlayHandle); //EVROverlayError err = overlay.CreateDashboardOverlay(Config.Key, Config.Name, ref m_OverlayHandle, ref m_ThumbnailIcon); @@ -224,7 +226,7 @@ namespace VRDash.Overlay if (!succ) { - this.GetLogger().Warn($"[{Config.Name}] SetCursorPos failed."); + this.GetLogger().Warn($"SetCursorPos failed."); } break; @@ -356,6 +358,13 @@ namespace VRDash.Overlay break; } } + break; + } + case EVREventType.VREvent_ScrollDiscrete: + { + var scrollAmount = vrEvent.data.scroll.ydelta; + User32.mouse_event(User32.MouseEventFlags.MOUSEEVENTF_WHEEL, 0, 0, (uint)(scrollAmount * 100), UIntPtr.Zero); + break; } } @@ -400,13 +409,13 @@ namespace VRDash.Overlay } else { - this.GetLogger().Warn($"[{Config.Name}] Error getting coords to draw cursor."); + this.GetLogger().Warn($"Error getting coords to draw cursor."); } } else { string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message; - this.GetLogger().Warn($"[{Config.Name}] Error getting cursor info: {errorMessage}"); + this.GetLogger().Warn($"Error getting cursor info: {errorMessage}"); } #endregion @@ -447,7 +456,7 @@ namespace VRDash.Overlay HmdVector2_t vecWindowSize = new HmdVector2_t() { v0 = data.Width, v1 = data.Height }; OpenVR.Overlay.SetOverlayMouseScale(m_OverlayHandle, ref vecWindowSize); - this.GetLogger().Info($"[{Config.Name}] Monitor resized, texture updated."); + this.GetLogger().Info($"Monitor resized, texture updated."); } diff --git a/VRDash/Overlay/WindowOverlay.cs b/VRDash/Overlay/WindowOverlay.cs index 6a17b96..03a40f5 100644 --- a/VRDash/Overlay/WindowOverlay.cs +++ b/VRDash/Overlay/WindowOverlay.cs @@ -103,18 +103,18 @@ namespace VRDash.Overlay { m_Destroyed = true; destroyInternal(); - } - - private void destroyInternal() - { - if (!m_Created) { return; } - m_Created = false; //Signal render thread to exit m_Running = false; //Wait for render thread to exit m_EventPumpTask.Wait(); + } + + private void destroyInternal() + { + if (!m_Created) { return; } + m_Created = false; var err = OpenVR.Overlay.DestroyOverlay(m_OverlayHandle); @@ -133,10 +133,10 @@ namespace VRDash.Overlay DateTime lastClick = DateTime.MinValue; - - Config.Initialize(this); + overlay.SetOverlayFlag(m_OverlayHandle, VROverlayFlags.SendVRDiscreteScrollEvents, true); + #region Rendering setup //Partially taken from here: https://stackoverflow.com/questions/6812068/c-sharp-which-is-the-fastest-way-to-take-a-screen-shot @@ -176,7 +176,7 @@ namespace VRDash.Overlay if (IsCreated()) { destroyInternal(); - this.GetLogger().Info($"Destroyed {Config.Key} because it's window does not exist."); + this.GetLogger().Info($"Destroyed overlay because it's window does not exist."); } Thread.Sleep(100); @@ -185,18 +185,11 @@ namespace VRDash.Overlay else if(Config.Selector.WindowExists() && !m_Created && !m_Destroyed) { createInternal(); + this.GetLogger().Info($"Instantiated overlay because window became available."); } } - //This technically should never happen, buuuut... - IntPtr windowHandle = IntPtr.Zero; - try - { - windowHandle = Config.Selector.GetWindowHandle(); - } - catch (WindowNotFoundException) - { - } + var windowHandle = Config.Selector.GetWindowHandle(); //Update the SteamVR dash name if necessary, only once a second. if (Config.Selector.WindowExists() && Config.UpdateDashboardName && DateTime.Now.Subtract(lastNameCheck).TotalMilliseconds >= 1000) @@ -272,7 +265,7 @@ namespace VRDash.Overlay if (!succ) { - this.GetLogger().Warn($"[{Config.Name}] ClientToScreen failed."); + this.GetLogger().Warn($"ClientToScreen failed."); } @@ -280,7 +273,7 @@ namespace VRDash.Overlay if (!succ) { - this.GetLogger().Warn($"[{Config.Name}] SetCursorPos failed."); + this.GetLogger().Warn($"SetCursorPos failed."); } } break; @@ -418,6 +411,13 @@ namespace VRDash.Overlay break; } } + break; + } + case EVREventType.VREvent_ScrollDiscrete: + { + var scrollAmount = vrEvent.data.scroll.ydelta; + User32.mouse_event(User32.MouseEventFlags.MOUSEEVENTF_WHEEL, 0, 0, (uint)(scrollAmount * 100), UIntPtr.Zero); + break; } } @@ -467,13 +467,13 @@ namespace VRDash.Overlay } else { - this.GetLogger().Warn($"[{Config.Name}] Error getting coords to draw cursor."); + this.GetLogger().Warn($"Error getting coords to draw cursor."); } } else { string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message; - this.GetLogger().Warn($"[{Config.Name}] Error getting cursor info: {errorMessage}"); + this.GetLogger().Warn($"Error getting cursor info: {errorMessage}"); } #endregion @@ -514,7 +514,7 @@ namespace VRDash.Overlay HmdVector2_t vecWindowSize = new HmdVector2_t() { v0 = data.Width, v1 = data.Height }; OpenVR.Overlay.SetOverlayMouseScale(m_OverlayHandle, ref vecWindowSize); - this.GetLogger().Info($"[{Config.Name}] Window resized, texture updated."); + this.GetLogger().Info($"Window resized, texture updated."); } @@ -596,8 +596,15 @@ namespace VRDash.Overlay if (DateTime.Now.Subtract(lastFps).TotalMilliseconds > 1000) { - //Console.WriteLine($"{frames} fps."); - CurrentFPS = frames; + if (Config.Selector.WindowExists()) + { + CurrentFPS = frames; + } + else + { + CurrentFPS = 0; + } + frames = 0; lastFps = DateTime.Now; } diff --git a/VRDash/UI/CreateNewOverlay.xaml b/VRDash/UI/CreateNewOverlay.xaml index 6d7dc1b..7a97ffa 100644 --- a/VRDash/UI/CreateNewOverlay.xaml +++ b/VRDash/UI/CreateNewOverlay.xaml @@ -15,7 +15,7 @@ - + diff --git a/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml b/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml index ba01c2c..6809cac 100644 --- a/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml +++ b/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml @@ -11,25 +11,68 @@ + + - - - + + + + - - - + + Controller: + + + + + Position: + + X: + + + + Y: + + + + Z: + + - - - + Rotation: + + P: + + + + Y: + + + + R: + + - - - + Scale: + + X: + + + + Y: + + + + Z: + + + + Preset: + + diff --git a/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml.cs b/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml.cs index ce0c7f7..c83fd53 100644 --- a/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml.cs +++ b/VRDash/UI/LocationEditors/ControllerLocationEditor.xaml.cs @@ -22,16 +22,79 @@ namespace VRDash.UI.LocationEditors public partial class ControllerLocationEditor : UserControl { public ControllerLocation Location { get; set; } = null; + public Preset[] Presets = { new Preset() {Description = "Default" }, new Preset() { Description = "Behind Controller", PosY = -0.1f, RotP = -90, RotY = 180 } }; public ControllerLocationEditor(ControllerLocation loction) { Location = loction; InitializeComponent(); DataContext = this; + cbController.ItemsSource = Enum.GetValues(typeof(ControllerLocation.ControllerHand)); + cbPresets.ItemsSource = Presets; } private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { Location.ResetCheckTimer(); } + + public class Preset + { + public string Description { get; set; } + public float PosX { get; set; } = 0; + public float PosY { get; set; } = 0; + public float PosZ { get; set; } = 0; + + public float RotP { get; set; } = 0; + public float RotY { get; set; } = 0; + public float RotR { get; set; } = 0; + + public float ScaleX { get; set; } = 1; + public float ScaleY { get; set; } = 1; + public float ScaleZ { get; set; } = 1; + + public override string ToString() + { + return Description; + } + } + + private void cbPresets_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + Preset preset = (Preset)cbPresets.SelectedItem; + Location.PosX = preset.PosX; + Location.PosY = preset.PosY; + Location.PosZ = preset.PosZ; + + Location.RotP = preset.RotP; + Location.RotY = preset.RotY; + Location.RotR = preset.RotR; + + Location.ScaleX = preset.ScaleX; + Location.ScaleY = preset.ScaleY; + Location.ScaleZ = preset.ScaleZ; + + Panel container = (Panel)this.Content; + UIElementCollection children = container.Children; + + List lstElement = children.Cast().ToList(); + + var lstControl = lstElement.OfType(); + + foreach(var control in children) + { + if (control.GetType() == typeof(DockPanel)) + { + var dockPanel = (DockPanel)control; + foreach (var dcChild in dockPanel.Children) + { + if(dcChild.GetType() == typeof(TextBox)) + { + var tb = (TextBox)dcChild; + tb.GetBindingExpression(TextBox.TextProperty).UpdateTarget(); + } + } + } + } + } } } diff --git a/VRDash/UI/OverlayEditor.xaml b/VRDash/UI/OverlayEditor.xaml index 36607b4..a93a004 100644 --- a/VRDash/UI/OverlayEditor.xaml +++ b/VRDash/UI/OverlayEditor.xaml @@ -8,8 +8,8 @@ d:DesignHeight="450" d:DesignWidth="800"> - + @@ -17,12 +17,16 @@ - - + + + + + Overlay Width: + diff --git a/VRDash/WindowSelectors/FromProcessName.cs b/VRDash/WindowSelectors/FromProcessName.cs index 20f4aaf..211c1b8 100644 --- a/VRDash/WindowSelectors/FromProcessName.cs +++ b/VRDash/WindowSelectors/FromProcessName.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using VRDash.Utilities; namespace VRDash.WindowSelectors @@ -38,18 +39,40 @@ namespace VRDash.WindowSelectors } Process[] m_Processes = null; + public Process[] GetProcesses() { if(m_Processes == null) { - m_Processes = Process.GetProcessesByName(ProcessName); + RefreshProcesses(); } return m_Processes; } + private void RefreshProcesses() + { + m_Processes = Process.GetProcessesByName(ProcessName); + } + + DateTime m_LastCheck = DateTime.MinValue; + bool isRefreshing = false; public Process GetProcess() { + if(m_Processes != null && DateTime.Now.Subtract(m_LastCheck).TotalSeconds > 10) + { + if (!isRefreshing) + { + Task.Factory.StartNew(() => + { + isRefreshing = true; + RefreshProcesses(); + + isRefreshing = false; + m_LastCheck = DateTime.Now; + }); + } + } var procs = GetProcesses(); if (procs.Count() <= 0) @@ -58,6 +81,7 @@ namespace VRDash.WindowSelectors } return procs.First(); } + public IntPtr GetWindowHandle() { return GetProcess().MainWindowHandle; @@ -75,14 +99,7 @@ namespace VRDash.WindowSelectors public bool WindowExists() { - try - { - return User32.IsWindow(GetWindowHandle()); - } - catch - { - return false; - } + return WindowInfo.GetWindowList().Any(x => x.hWnd == GetWindowHandle()); } } } diff --git a/VRDash/WindowSelectors/FromWindowTitle.cs b/VRDash/WindowSelectors/FromWindowTitle.cs index 595fe9a..b1dc0f9 100644 --- a/VRDash/WindowSelectors/FromWindowTitle.cs +++ b/VRDash/WindowSelectors/FromWindowTitle.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; using VRDash.Utilities; namespace VRDash.WindowSelectors @@ -12,6 +13,8 @@ namespace VRDash.WindowSelectors public bool RefreshOnGet { get; set; } = false; public string TitleFilter { get; set; } = ""; public TitleSearchType SearchType { get; set; } = TitleSearchType.Contains; + DateTime m_LastCheck = DateTime.MinValue; + bool isRefreshing = false; [JsonIgnore] public WindowInfo Window @@ -25,6 +28,20 @@ namespace VRDash.WindowSelectors } else { + //Auto refreshing. Might be better to not do this in the getter, but whatever. + if(DateTime.Now.Subtract(m_LastCheck).TotalSeconds > 10) + { + if (!isRefreshing) + { + Task.Factory.StartNew(() => + { + isRefreshing = true; + m_Window = GetWindowUsingFilter(); + m_LastCheck = DateTime.Now; + isRefreshing = false; + }); + } + } if (m_Window == null) { m_Window = GetWindowUsingFilter(); @@ -94,15 +111,6 @@ namespace VRDash.WindowSelectors public bool WindowExists() { - //try - //{ - // var window = Window; - //} - //catch (WindowNotFoundException) - //{ - // return false; - //} - //return true; if(Window == null) { return false;