IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
ControllerButtonHints.cs
1 //======= Copyright (c) Valve Corporation, All rights reserved. ===============
2 //
3 // Purpose: Displays text and button hints on the controllers
4 //
5 //=============================================================================
6 
7 using UnityEngine;
8 using System.Collections;
9 using System.Collections.Generic;
10 using UnityEngine.UI;
11 
12 namespace Valve.VR.InteractionSystem
13 {
14  //-------------------------------------------------------------------------
15  public class ControllerButtonHints : MonoBehaviour
16  {
17  public Material controllerMaterial;
18  public Color flashColor = new Color( 1.0f, 0.557f, 0.0f );
19  public GameObject textHintPrefab;
20 
21  [Header( "Debug" )]
22  public bool debugHints = false;
23 
24  private SteamVR_RenderModel renderModel;
25  private Player player;
26 
27  private List<MeshRenderer> renderers = new List<MeshRenderer>();
28  private List<MeshRenderer> flashingRenderers = new List<MeshRenderer>();
29  private float startTime;
30  private float tickCount;
31 
32  private enum OffsetType
33  {
34  Up,
35  Right,
36  Forward,
37  Back
38  }
39 
40  //Info for each of the buttons
41  private class ButtonHintInfo
42  {
43  public string componentName;
44  public List<MeshRenderer> renderers;
45  public Transform localTransform;
46 
47  //Text hint
48  public GameObject textHintObject;
49  public Transform textStartAnchor;
50  public Transform textEndAnchor;
51  public Vector3 textEndOffsetDir;
52  public Transform canvasOffset;
53 
54  public Text text;
55  public TextMesh textMesh;
56  public Canvas textCanvas;
57  public LineRenderer line;
58 
59  public float distanceFromCenter;
60  public bool textHintActive = false;
61  }
62 
63  private Dictionary<EVRButtonId, ButtonHintInfo> buttonHintInfos;
64  private Transform textHintParent;
65  private List<KeyValuePair<string, ulong>> componentButtonMasks = new List<KeyValuePair<string, ulong>>();
66 
67  private int colorID;
68 
69  public bool initialized { get; private set; }
70  private Vector3 centerPosition = Vector3.zero;
71 
72  SteamVR_Events.Action renderModelLoadedAction;
73 
74 
75  //-------------------------------------------------
76  void Awake()
77  {
78  renderModelLoadedAction = SteamVR_Events.RenderModelLoadedAction( OnRenderModelLoaded );
79  colorID = Shader.PropertyToID( "_Color" );
80  }
81 
82 
83  //-------------------------------------------------
84  void Start()
85  {
86  player = Player.instance;
87  }
88 
89 
90  //-------------------------------------------------
91  private void HintDebugLog( string msg )
92  {
93  if ( debugHints )
94  {
95  Debug.Log( "Hints: " + msg );
96  }
97  }
98 
99 
100  //-------------------------------------------------
101  void OnEnable()
102  {
103  renderModelLoadedAction.enabled = true;
104  }
105 
106 
107  //-------------------------------------------------
108  void OnDisable()
109  {
110  renderModelLoadedAction.enabled = false;
111  Clear();
112  }
113 
114 
115  //-------------------------------------------------
116  private void OnParentHandInputFocusLost()
117  {
118  //Hide all the hints when the controller is no longer the primary attached object
119  HideAllButtonHints();
120  HideAllText();
121  }
122 
123 
124  //-------------------------------------------------
125  // Gets called when the hand has been initialized and a render model has been set
126  //-------------------------------------------------
127  private void OnHandInitialized( int deviceIndex )
128  {
129  //Create a new render model for the controller hints
130  renderModel = new GameObject( "SteamVR_RenderModel" ).AddComponent<SteamVR_RenderModel>();
131  renderModel.transform.parent = transform;
132  renderModel.transform.localPosition = Vector3.zero;
133  renderModel.transform.localRotation = Quaternion.identity;
134  renderModel.transform.localScale = Vector3.one;
135  renderModel.SetDeviceIndex( deviceIndex );
136 
137  if ( !initialized )
138  {
139  //The controller hint render model needs to be active to get accurate transforms for all the individual components
140  renderModel.gameObject.SetActive( true );
141  }
142  }
143 
144 
145  //-------------------------------------------------
146  void OnRenderModelLoaded( SteamVR_RenderModel renderModel, bool succeess )
147  {
148  //Only initialize when the render model for the controller hints has been loaded
149  if ( renderModel == this.renderModel )
150  {
151  textHintParent = new GameObject( "Text Hints" ).transform;
152  textHintParent.SetParent( this.transform );
153  textHintParent.localPosition = Vector3.zero;
154  textHintParent.localRotation = Quaternion.identity;
155  textHintParent.localScale = Vector3.one;
156 
157  //Get the button mask for each component of the render model
158  using ( var holder = new SteamVR_RenderModel.RenderModelInterfaceHolder() )
159  {
160  var renderModels = holder.instance;
161  if ( renderModels != null )
162  {
163  string renderModelDebug = "Components for render model " + renderModel.index;
164  foreach ( Transform child in renderModel.transform )
165  {
166  ulong buttonMask = renderModels.GetComponentButtonMask( renderModel.renderModelName, child.name );
167 
168  componentButtonMasks.Add( new KeyValuePair<string, ulong>( child.name, buttonMask ) );
169 
170  renderModelDebug += "\n\t" + child.name + ": " + buttonMask;
171  }
172 
173  //Uncomment to show the button mask for each component of the render model
174  HintDebugLog( renderModelDebug );
175  }
176  }
177 
178  buttonHintInfos = new Dictionary<EVRButtonId, ButtonHintInfo>();
179 
180  CreateAndAddButtonInfo( EVRButtonId.k_EButton_SteamVR_Trigger );
181  CreateAndAddButtonInfo( EVRButtonId.k_EButton_ApplicationMenu );
182  CreateAndAddButtonInfo( EVRButtonId.k_EButton_System );
183  CreateAndAddButtonInfo( EVRButtonId.k_EButton_Grip );
184  CreateAndAddButtonInfo( EVRButtonId.k_EButton_SteamVR_Touchpad );
185  CreateAndAddButtonInfo( EVRButtonId.k_EButton_A );
186 
187  ComputeTextEndTransforms();
188 
189  initialized = true;
190 
191  //Set the controller hints render model to not active
192  renderModel.gameObject.SetActive( false );
193  }
194  }
195 
196 
197  //-------------------------------------------------
198  private void CreateAndAddButtonInfo( EVRButtonId buttonID )
199  {
200  Transform buttonTransform = null;
201  List<MeshRenderer> buttonRenderers = new List<MeshRenderer>();
202 
203  string buttonDebug = "Looking for button: " + buttonID;
204 
205  EVRButtonId searchButtonID = buttonID;
206  if ( buttonID == EVRButtonId.k_EButton_Grip && SteamVR.instance.hmd_TrackingSystemName.ToLowerInvariant().Contains( "oculus" ) )
207  {
208  searchButtonID = EVRButtonId.k_EButton_Axis2;
209  }
210  ulong buttonMaskForID = ( 1ul << (int)searchButtonID );
211 
212  foreach ( KeyValuePair<string, ulong> componentButtonMask in componentButtonMasks )
213  {
214  if ( ( componentButtonMask.Value & buttonMaskForID ) == buttonMaskForID )
215  {
216  buttonDebug += "\nFound component: " + componentButtonMask.Key + " " + componentButtonMask.Value;
217  Transform componentTransform = renderModel.FindComponent( componentButtonMask.Key );
218 
219  buttonTransform = componentTransform;
220 
221  buttonDebug += "\nFound componentTransform: " + componentTransform + " buttonTransform: " + buttonTransform;
222 
223  buttonRenderers.AddRange( componentTransform.GetComponentsInChildren<MeshRenderer>() );
224  }
225  }
226 
227  buttonDebug += "\nFound " + buttonRenderers.Count + " renderers for " + buttonID;
228  foreach ( MeshRenderer renderer in buttonRenderers )
229  {
230  buttonDebug += "\n\t" + renderer.name;
231  }
232 
233  HintDebugLog( buttonDebug );
234 
235  if ( buttonTransform == null )
236  {
237  HintDebugLog( "Couldn't find buttonTransform for " + buttonID );
238  return;
239  }
240 
241  ButtonHintInfo hintInfo = new ButtonHintInfo();
242  buttonHintInfos.Add( buttonID, hintInfo );
243 
244  hintInfo.componentName = buttonTransform.name;
245  hintInfo.renderers = buttonRenderers;
246 
247  //Get the local transform for the button
248  hintInfo.localTransform = buttonTransform.Find( SteamVR_RenderModel.k_localTransformName );
249 
250  OffsetType offsetType = OffsetType.Right;
251  switch ( buttonID )
252  {
253  case EVRButtonId.k_EButton_SteamVR_Trigger:
254  {
255  offsetType = OffsetType.Right;
256  }
257  break;
258  case EVRButtonId.k_EButton_ApplicationMenu:
259  {
260  offsetType = OffsetType.Right;
261  }
262  break;
263  case EVRButtonId.k_EButton_System:
264  {
265  offsetType = OffsetType.Right;
266  }
267  break;
268  case Valve.VR.EVRButtonId.k_EButton_Grip:
269  {
270  offsetType = OffsetType.Forward;
271  }
272  break;
273  case Valve.VR.EVRButtonId.k_EButton_SteamVR_Touchpad:
274  {
275  offsetType = OffsetType.Up;
276  }
277  break;
278  }
279 
280  //Offset for the text end transform
281  switch ( offsetType )
282  {
283  case OffsetType.Forward:
284  hintInfo.textEndOffsetDir = hintInfo.localTransform.forward;
285  break;
286  case OffsetType.Back:
287  hintInfo.textEndOffsetDir = -hintInfo.localTransform.forward;
288  break;
289  case OffsetType.Right:
290  hintInfo.textEndOffsetDir = hintInfo.localTransform.right;
291  break;
292  case OffsetType.Up:
293  hintInfo.textEndOffsetDir = hintInfo.localTransform.up;
294  break;
295  }
296 
297  //Create the text hint object
298  Vector3 hintStartPos = hintInfo.localTransform.position + ( hintInfo.localTransform.forward * 0.01f );
299  hintInfo.textHintObject = GameObject.Instantiate( textHintPrefab, hintStartPos, Quaternion.identity ) as GameObject;
300  hintInfo.textHintObject.name = "Hint_" + hintInfo.componentName + "_Start";
301  hintInfo.textHintObject.transform.SetParent( textHintParent );
302  hintInfo.textHintObject.layer = gameObject.layer;
303  hintInfo.textHintObject.tag = gameObject.tag;
304 
305  //Get all the relevant child objects
306  hintInfo.textStartAnchor = hintInfo.textHintObject.transform.Find( "Start" );
307  hintInfo.textEndAnchor = hintInfo.textHintObject.transform.Find( "End" );
308  hintInfo.canvasOffset = hintInfo.textHintObject.transform.Find( "CanvasOffset" );
309  hintInfo.line = hintInfo.textHintObject.transform.Find( "Line" ).GetComponent<LineRenderer>();
310  hintInfo.textCanvas = hintInfo.textHintObject.GetComponentInChildren<Canvas>();
311  hintInfo.text = hintInfo.textCanvas.GetComponentInChildren<Text>();
312  hintInfo.textMesh = hintInfo.textCanvas.GetComponentInChildren<TextMesh>();
313 
314  hintInfo.textHintObject.SetActive( false );
315 
316  hintInfo.textStartAnchor.position = hintStartPos;
317 
318  if ( hintInfo.text != null )
319  {
320  hintInfo.text.text = hintInfo.componentName;
321  }
322 
323  if ( hintInfo.textMesh != null )
324  {
325  hintInfo.textMesh.text = hintInfo.componentName;
326  }
327 
328  centerPosition += hintInfo.textStartAnchor.position;
329 
330  // Scale hint components to match player size
331  hintInfo.textCanvas.transform.localScale = Vector3.Scale( hintInfo.textCanvas.transform.localScale, player.transform.localScale );
332  hintInfo.textStartAnchor.transform.localScale = Vector3.Scale( hintInfo.textStartAnchor.transform.localScale, player.transform.localScale );
333  hintInfo.textEndAnchor.transform.localScale = Vector3.Scale( hintInfo.textEndAnchor.transform.localScale, player.transform.localScale );
334  hintInfo.line.transform.localScale = Vector3.Scale( hintInfo.line.transform.localScale, player.transform.localScale );
335  }
336 
337 
338  //-------------------------------------------------
339  private void ComputeTextEndTransforms()
340  {
341  //This is done as a separate step after all the ButtonHintInfos have been initialized
342  //to make the text hints fan out appropriately based on the button's position on the controller.
343 
344  centerPosition /= buttonHintInfos.Count;
345  float maxDistanceFromCenter = 0.0f;
346 
347  foreach ( var hintInfo in buttonHintInfos )
348  {
349  hintInfo.Value.distanceFromCenter = Vector3.Distance( hintInfo.Value.textStartAnchor.position, centerPosition );
350 
351  if ( hintInfo.Value.distanceFromCenter > maxDistanceFromCenter )
352  {
353  maxDistanceFromCenter = hintInfo.Value.distanceFromCenter;
354  }
355  }
356 
357  foreach ( var hintInfo in buttonHintInfos )
358  {
359  Vector3 centerToButton = hintInfo.Value.textStartAnchor.position - centerPosition;
360  centerToButton.Normalize();
361 
362  centerToButton = Vector3.Project( centerToButton, renderModel.transform.forward );
363 
364  //Spread out the text end positions based on the distance from the center
365  float t = hintInfo.Value.distanceFromCenter / maxDistanceFromCenter;
366  float scale = hintInfo.Value.distanceFromCenter * Mathf.Pow( 2, 10 * ( t - 1.0f ) ) * 20.0f;
367 
368  //Flip the direction of the end pos based on which hand this is
369  float endPosOffset = 0.1f;
370 
371  Vector3 hintEndPos = hintInfo.Value.textStartAnchor.position + ( hintInfo.Value.textEndOffsetDir * endPosOffset ) + ( centerToButton * scale * 0.1f );
372  hintInfo.Value.textEndAnchor.position = hintEndPos;
373 
374  hintInfo.Value.canvasOffset.position = hintEndPos;
375  hintInfo.Value.canvasOffset.localRotation = Quaternion.identity;
376  }
377  }
378 
379 
380  //-------------------------------------------------
381  private void ShowButtonHint( params EVRButtonId[] buttons )
382  {
383  renderModel.gameObject.SetActive( true );
384 
385  renderModel.GetComponentsInChildren<MeshRenderer>( renderers );
386  for ( int i = 0; i < renderers.Count; i++ )
387  {
388  Texture mainTexture = renderers[i].material.mainTexture;
389  renderers[i].sharedMaterial = controllerMaterial;
390  renderers[i].material.mainTexture = mainTexture;
391 
392  // This is to poke unity into setting the correct render queue for the model
393  renderers[i].material.renderQueue = controllerMaterial.shader.renderQueue;
394  }
395 
396  for ( int i = 0; i < buttons.Length; i++ )
397  {
398  if ( buttonHintInfos.ContainsKey( buttons[i] ) )
399  {
400  ButtonHintInfo hintInfo = buttonHintInfos[buttons[i]];
401  foreach ( MeshRenderer renderer in hintInfo.renderers )
402  {
403  if ( !flashingRenderers.Contains( renderer ) )
404  {
405  flashingRenderers.Add( renderer );
406  }
407  }
408  }
409  }
410 
411  startTime = Time.realtimeSinceStartup;
412  tickCount = 0.0f;
413  }
414 
415 
416  //-------------------------------------------------
417  private void HideAllButtonHints()
418  {
419  Clear();
420 
421  renderModel.gameObject.SetActive( false );
422  }
423 
424 
425  //-------------------------------------------------
426  private void HideButtonHint( params EVRButtonId[] buttons )
427  {
428  Color baseColor = controllerMaterial.GetColor( colorID );
429  for ( int i = 0; i < buttons.Length; i++ )
430  {
431  if ( buttonHintInfos.ContainsKey( buttons[i] ) )
432  {
433  ButtonHintInfo hintInfo = buttonHintInfos[buttons[i]];
434  foreach ( MeshRenderer renderer in hintInfo.renderers )
435  {
436  renderer.material.color = baseColor;
437  flashingRenderers.Remove( renderer );
438  }
439  }
440  }
441 
442  if ( flashingRenderers.Count == 0 )
443  {
444  renderModel.gameObject.SetActive( false );
445  }
446  }
447 
448 
449 
450 
451  //-------------------------------------------------
452  private bool IsButtonHintActive( EVRButtonId button )
453  {
454  if ( buttonHintInfos.ContainsKey( button ) )
455  {
456  ButtonHintInfo hintInfo = buttonHintInfos[button];
457  foreach ( MeshRenderer buttonRenderer in hintInfo.renderers )
458  {
459  if ( flashingRenderers.Contains( buttonRenderer ) )
460  {
461  return true;
462  }
463  }
464  }
465 
466  return false;
467  }
468 
469 
470  //-------------------------------------------------
471  private IEnumerator TestButtonHints()
472  {
473  while ( true )
474  {
475  ShowButtonHint( EVRButtonId.k_EButton_SteamVR_Trigger );
476  yield return new WaitForSeconds( 1.0f );
477  ShowButtonHint( EVRButtonId.k_EButton_ApplicationMenu );
478  yield return new WaitForSeconds( 1.0f );
479  ShowButtonHint( EVRButtonId.k_EButton_System );
480  yield return new WaitForSeconds( 1.0f );
481  ShowButtonHint( EVRButtonId.k_EButton_Grip );
482  yield return new WaitForSeconds( 1.0f );
483  ShowButtonHint( EVRButtonId.k_EButton_SteamVR_Touchpad );
484  yield return new WaitForSeconds( 1.0f );
485  }
486  }
487 
488 
489  //-------------------------------------------------
490  private IEnumerator TestTextHints()
491  {
492  while ( true )
493  {
494  ShowText( EVRButtonId.k_EButton_SteamVR_Trigger, "Trigger" );
495  yield return new WaitForSeconds( 3.0f );
496  ShowText( EVRButtonId.k_EButton_ApplicationMenu, "Application" );
497  yield return new WaitForSeconds( 3.0f );
498  ShowText( EVRButtonId.k_EButton_System, "System" );
499  yield return new WaitForSeconds( 3.0f );
500  ShowText( EVRButtonId.k_EButton_Grip, "Grip" );
501  yield return new WaitForSeconds( 3.0f );
502  ShowText( EVRButtonId.k_EButton_SteamVR_Touchpad, "Touchpad" );
503  yield return new WaitForSeconds( 3.0f );
504 
505  HideAllText();
506  yield return new WaitForSeconds( 3.0f );
507  }
508  }
509 
510 
511  //-------------------------------------------------
512  void Update()
513  {
514  if ( renderModel != null && renderModel.gameObject.activeInHierarchy && flashingRenderers.Count > 0 )
515  {
516  Color baseColor = controllerMaterial.GetColor( colorID );
517 
518  float flash = ( Time.realtimeSinceStartup - startTime ) * Mathf.PI * 2.0f;
519  flash = Mathf.Cos( flash );
520  flash = Util.RemapNumberClamped( flash, -1.0f, 1.0f, 0.0f, 1.0f );
521 
522  float ticks = ( Time.realtimeSinceStartup - startTime );
523  if ( ticks - tickCount > 1.0f )
524  {
525  tickCount += 1.0f;
526  SteamVR_Controller.Device device = SteamVR_Controller.Input( (int)renderModel.index );
527  if ( device != null )
528  {
529  device.TriggerHapticPulse();
530  }
531  }
532 
533  for ( int i = 0; i < flashingRenderers.Count; i++ )
534  {
535  Renderer r = flashingRenderers[i];
536  r.material.SetColor( colorID, Color.Lerp( baseColor, flashColor, flash ) );
537  }
538 
539  if ( initialized )
540  {
541  foreach ( var hintInfo in buttonHintInfos )
542  {
543  if ( hintInfo.Value.textHintActive )
544  {
545  UpdateTextHint( hintInfo.Value );
546  }
547  }
548  }
549  }
550  }
551 
552 
553  //-------------------------------------------------
554  private void UpdateTextHint( ButtonHintInfo hintInfo )
555  {
556  Transform playerTransform = player.hmdTransform;
557  Vector3 vDir = playerTransform.position - hintInfo.canvasOffset.position;
558 
559  Quaternion standardLookat = Quaternion.LookRotation( vDir, Vector3.up );
560  Quaternion upsideDownLookat = Quaternion.LookRotation( vDir, playerTransform.up );
561 
562  float flInterp;
563  if ( playerTransform.forward.y > 0.0f )
564  {
565  flInterp = Util.RemapNumberClamped( playerTransform.forward.y, 0.6f, 0.4f, 1.0f, 0.0f );
566  }
567  else
568  {
569  flInterp = Util.RemapNumberClamped( playerTransform.forward.y, -0.8f, -0.6f, 1.0f, 0.0f );
570  }
571 
572  hintInfo.canvasOffset.rotation = Quaternion.Slerp( standardLookat, upsideDownLookat, flInterp );
573 
574  Transform lineTransform = hintInfo.line.transform;
575 
576  hintInfo.line.useWorldSpace = false;
577  hintInfo.line.SetPosition( 0, lineTransform.InverseTransformPoint( hintInfo.textStartAnchor.position ) );
578  hintInfo.line.SetPosition( 1, lineTransform.InverseTransformPoint( hintInfo.textEndAnchor.position ) );
579  }
580 
581 
582  //-------------------------------------------------
583  private void Clear()
584  {
585  renderers.Clear();
586  flashingRenderers.Clear();
587  }
588 
589 
590  //-------------------------------------------------
591  private void ShowText( EVRButtonId button, string text, bool highlightButton = true )
592  {
593  if ( buttonHintInfos.ContainsKey( button ) )
594  {
595  ButtonHintInfo hintInfo = buttonHintInfos[button];
596  hintInfo.textHintObject.SetActive( true );
597  hintInfo.textHintActive = true;
598 
599  if ( hintInfo.text != null )
600  {
601  hintInfo.text.text = text;
602  }
603 
604  if ( hintInfo.textMesh != null )
605  {
606  hintInfo.textMesh.text = text;
607  }
608 
609  UpdateTextHint( hintInfo );
610 
611  if ( highlightButton )
612  {
613  ShowButtonHint( button );
614  }
615 
616  renderModel.gameObject.SetActive( true );
617  }
618  }
619 
620 
621  //-------------------------------------------------
622  private void HideText( EVRButtonId button )
623  {
624  if ( buttonHintInfos.ContainsKey( button ) )
625  {
626  ButtonHintInfo hintInfo = buttonHintInfos[button];
627  hintInfo.textHintObject.SetActive( false );
628  hintInfo.textHintActive = false;
629 
630  HideButtonHint( button );
631  }
632  }
633 
634 
635  //-------------------------------------------------
636  private void HideAllText()
637  {
638  foreach ( var hintInfo in buttonHintInfos )
639  {
640  hintInfo.Value.textHintObject.SetActive( false );
641  hintInfo.Value.textHintActive = false;
642  }
643 
644  HideAllButtonHints();
645  }
646 
647 
648  //-------------------------------------------------
649  private string GetActiveHintText( EVRButtonId button )
650  {
651  if ( buttonHintInfos.ContainsKey( button ) )
652  {
653  ButtonHintInfo hintInfo = buttonHintInfos[button];
654  if ( hintInfo.textHintActive )
655  {
656  return hintInfo.text.text;
657  }
658  }
659  return string.Empty;
660  }
661 
662 
663  //-------------------------------------------------
664  // These are the static functions which are used to show/hide the hints
665  //-------------------------------------------------
666 
667  //-------------------------------------------------
668  private static ControllerButtonHints GetControllerButtonHints( Hand hand )
669  {
670  if ( hand != null )
671  {
672  ControllerButtonHints hints = hand.GetComponentInChildren<ControllerButtonHints>();
673  if ( hints != null && hints.initialized )
674  {
675  return hints;
676  }
677  }
678 
679  return null;
680  }
681 
682 
683  //-------------------------------------------------
684  public static void ShowButtonHint( Hand hand, params EVRButtonId[] buttons )
685  {
686  ControllerButtonHints hints = GetControllerButtonHints( hand );
687  if ( hints != null )
688  {
689  hints.ShowButtonHint( buttons );
690  }
691  }
692 
693 
694  //-------------------------------------------------
695  public static void HideButtonHint( Hand hand, params EVRButtonId[] buttons )
696  {
697  ControllerButtonHints hints = GetControllerButtonHints( hand );
698  if ( hints != null )
699  {
700  hints.HideButtonHint( buttons );
701  }
702  }
703 
704 
705  //-------------------------------------------------
706  public static void HideAllButtonHints( Hand hand )
707  {
708  ControllerButtonHints hints = GetControllerButtonHints( hand );
709  if ( hints != null )
710  {
711  hints.HideAllButtonHints();
712  }
713  }
714 
715 
716  //-------------------------------------------------
717  public static bool IsButtonHintActive( Hand hand, EVRButtonId button )
718  {
719  ControllerButtonHints hints = GetControllerButtonHints( hand );
720  if ( hints != null )
721  {
722  return hints.IsButtonHintActive( button );
723  }
724 
725  return false;
726  }
727 
728 
729  //-------------------------------------------------
730  public static void ShowTextHint( Hand hand, EVRButtonId button, string text, bool highlightButton = true )
731  {
732  ControllerButtonHints hints = GetControllerButtonHints( hand );
733  if ( hints != null )
734  {
735  hints.ShowText( button, text, highlightButton );
736  }
737  }
738 
739 
740  //-------------------------------------------------
741  public static void HideTextHint( Hand hand, EVRButtonId button )
742  {
743  ControllerButtonHints hints = GetControllerButtonHints( hand );
744  if ( hints != null )
745  {
746  hints.HideText( button );
747  }
748  }
749 
750 
751  //-------------------------------------------------
752  public static void HideAllTextHints( Hand hand )
753  {
754  ControllerButtonHints hints = GetControllerButtonHints( hand );
755  if ( hints != null )
756  {
757  hints.HideAllText();
758  }
759  }
760 
761 
762  //-------------------------------------------------
763  public static string GetActiveHintText( Hand hand, EVRButtonId button )
764  {
765  ControllerButtonHints hints = GetControllerButtonHints( hand );
766  if ( hints != null )
767  {
768  return hints.GetActiveHintText( button );
769  }
770 
771  return string.Empty;
772  }
773  }
774 }