1+ using System ;
2+ using System . Windows ;
3+ using System . Windows . Controls ;
4+ using System . Windows . Input ;
5+ using Microsoft . Extensions . DependencyInjection ;
6+ using Microsoft . Extensions . Logging ;
7+ using VXMusicDesktop . Core ;
8+
9+ namespace VXMusicDesktop . Behaviors
10+ {
11+ public static class VRHapticBehavior
12+ {
13+ #region EnableHapticFeedback Attached Property
14+
15+ public static readonly DependencyProperty EnableHapticFeedbackProperty =
16+ DependencyProperty . RegisterAttached (
17+ "EnableHapticFeedback" ,
18+ typeof ( bool ) ,
19+ typeof ( VRHapticBehavior ) ,
20+ new PropertyMetadata ( false , OnEnableHapticFeedbackChanged ) ) ;
21+
22+ public static bool GetEnableHapticFeedback ( DependencyObject obj )
23+ {
24+ return ( bool ) obj . GetValue ( EnableHapticFeedbackProperty ) ;
25+ }
26+
27+ public static void SetEnableHapticFeedback ( DependencyObject obj , bool value )
28+ {
29+ obj . SetValue ( EnableHapticFeedbackProperty , value ) ;
30+ }
31+
32+ #endregion
33+
34+ #region HapticDuration Attached Property
35+
36+ public static readonly DependencyProperty HapticDurationProperty =
37+ DependencyProperty . RegisterAttached (
38+ "HapticDuration" ,
39+ typeof ( ushort ) ,
40+ typeof ( VRHapticBehavior ) ,
41+ new PropertyMetadata ( ( ushort ) 2000 ) ) ;
42+
43+ public static ushort GetHapticDuration ( DependencyObject obj )
44+ {
45+ return ( ushort ) obj . GetValue ( HapticDurationProperty ) ;
46+ }
47+
48+ public static void SetHapticDuration ( DependencyObject obj , ushort value )
49+ {
50+ obj . SetValue ( HapticDurationProperty , value ) ;
51+ }
52+
53+ #endregion
54+
55+ private static void OnEnableHapticFeedbackChanged ( DependencyObject d , DependencyPropertyChangedEventArgs e )
56+ {
57+ if ( d is FrameworkElement element )
58+ {
59+ bool enableHaptic = ( bool ) e . NewValue ;
60+
61+ if ( enableHaptic )
62+ {
63+ element . MouseEnter += OnElementMouseEnter ;
64+ element . Unloaded += OnElementUnloaded ;
65+ }
66+ else
67+ {
68+ element . MouseEnter -= OnElementMouseEnter ;
69+ element . Unloaded -= OnElementUnloaded ;
70+ }
71+ }
72+ }
73+
74+ private static void OnElementMouseEnter ( object sender , MouseEventArgs e )
75+ {
76+ if ( sender is FrameworkElement element )
77+ {
78+ // Only trigger haptic feedback for elements that can be interacted with
79+ if ( IsInteractiveElement ( element ) )
80+ {
81+ TriggerHapticFeedback ( element ) ;
82+ }
83+ }
84+ }
85+
86+ private static void OnElementUnloaded ( object sender , RoutedEventArgs e )
87+ {
88+ if ( sender is FrameworkElement element )
89+ {
90+ element . MouseEnter -= OnElementMouseEnter ;
91+ element . Unloaded -= OnElementUnloaded ;
92+ }
93+ }
94+
95+ private static bool IsInteractiveElement ( FrameworkElement element )
96+ {
97+ // Check if element is enabled and visible
98+ if ( ! element . IsEnabled || element . Visibility != Visibility . Visible )
99+ return false ;
100+
101+ // Check for common interactive elements
102+ switch ( element )
103+ {
104+ case Button button :
105+ return button . IsEnabled && button . Command ? . CanExecute ( button . CommandParameter ) != false ;
106+ case ComboBox comboBox :
107+ return comboBox . IsEnabled ;
108+ case RadioButton radioButton :
109+ return radioButton . IsEnabled ;
110+ case CheckBox checkBox :
111+ return checkBox . IsEnabled ;
112+ case TextBox textBox :
113+ return textBox . IsEnabled && ! textBox . IsReadOnly ;
114+ case ListBox listBox :
115+ return listBox . IsEnabled ;
116+ case MenuItem menuItem :
117+ return menuItem . IsEnabled ;
118+ case Slider slider :
119+ return slider . IsEnabled ;
120+ default :
121+ // For other elements, check if they have a cursor indicating interactivity
122+ return element . Cursor == Cursors . Hand || element . Cursor == Cursors . Arrow ;
123+ }
124+ }
125+
126+ private static void TriggerHapticFeedback ( FrameworkElement element )
127+ {
128+ try
129+ {
130+ // Get the haptic feedback service from the DI container
131+ var hapticService = App . ServiceProvider ? . GetService < IVRHapticFeedbackService > ( ) ;
132+ var loggerFactory = App . ServiceProvider ? . GetService < ILoggerFactory > ( ) ;
133+ var logger = loggerFactory ? . CreateLogger ( "VRHapticBehavior" ) ;
134+
135+ if ( hapticService != null )
136+ {
137+ ushort duration = GetHapticDuration ( element ) ;
138+ logger ? . LogDebug ( $ "Triggering haptic feedback for { element . GetType ( ) . Name } with duration { duration } ") ;
139+
140+ // Log VR system status
141+ logger ? . LogDebug ( $ "VR System Available: { hapticService . IsVRSystemAvailable ( ) } ") ;
142+ logger ? . LogDebug ( $ "Has Connected Controllers: { hapticService . HasConnectedControllers ( ) } ") ;
143+
144+ hapticService . TriggerHapticFeedback ( duration ) ;
145+ }
146+ else
147+ {
148+ logger ? . LogWarning ( "VRHapticFeedbackService not available from DI container" ) ;
149+ }
150+ }
151+ catch ( System . Exception ex )
152+ {
153+ // Log the exception if we have access to a logger
154+ try
155+ {
156+ // Try to get a logger factory and create a logger for haptic feedback
157+ var loggerFactory = App . ServiceProvider ? . GetService < ILoggerFactory > ( ) ;
158+ var logger = loggerFactory ? . CreateLogger ( "VRHapticBehavior" ) ;
159+ logger ? . LogWarning ( ex , "Failed to trigger haptic feedback from VRHapticBehavior" ) ;
160+ }
161+ catch
162+ {
163+ // If we can't even log, just silently fail to avoid breaking the UI
164+ }
165+ }
166+ }
167+ }
168+ }
0 commit comments