MouseButtonStateEx.cs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. /// <summary>
  4. /// Not to be confused with <see cref="NetEvents.MouseButtonState"/>
  5. /// </summary>
  6. internal class MouseButtonStateEx
  7. {
  8. private readonly Func<DateTime> _now;
  9. private readonly TimeSpan _repeatClickThreshold;
  10. private readonly int _buttonIdx;
  11. private int _consecutiveClicks;
  12. private Point _lastPosition;
  13. /// <summary>
  14. /// When the button entered its current state.
  15. /// </summary>
  16. public DateTime At { get; set; }
  17. /// <summary>
  18. /// <see langword="true"/> if the button is currently down
  19. /// </summary>
  20. public bool Pressed { get; set; }
  21. public MouseButtonStateEx (Func<DateTime> now, TimeSpan repeatClickThreshold, int buttonIdx)
  22. {
  23. _now = now;
  24. _repeatClickThreshold = repeatClickThreshold;
  25. _buttonIdx = buttonIdx;
  26. }
  27. public void UpdateState (MouseEventArgs e, out int? numClicks)
  28. {
  29. bool isPressedNow = IsPressed (_buttonIdx, e.Flags);
  30. bool isSamePosition = _lastPosition == e.Position;
  31. TimeSpan elapsed = _now () - At;
  32. if (elapsed > _repeatClickThreshold || !isSamePosition)
  33. {
  34. // Expired
  35. OverwriteState (e);
  36. _consecutiveClicks = 0;
  37. numClicks = null;
  38. }
  39. else
  40. {
  41. if (isPressedNow == Pressed)
  42. {
  43. // No change in button state so do nothing
  44. numClicks = null;
  45. return;
  46. }
  47. if (Pressed)
  48. {
  49. // Click released
  50. numClicks = ++_consecutiveClicks;
  51. }
  52. else
  53. {
  54. numClicks = null;
  55. }
  56. // Record new state
  57. OverwriteState (e);
  58. }
  59. }
  60. private void OverwriteState (MouseEventArgs e)
  61. {
  62. Pressed = IsPressed (_buttonIdx, e.Flags);
  63. At = _now ();
  64. _lastPosition = e.Position;
  65. }
  66. private bool IsPressed (int btn, MouseFlags eFlags)
  67. {
  68. return btn switch
  69. {
  70. 0 => eFlags.HasFlag (MouseFlags.Button1Pressed),
  71. 1 => eFlags.HasFlag (MouseFlags.Button2Pressed),
  72. 2 => eFlags.HasFlag (MouseFlags.Button3Pressed),
  73. 3 => eFlags.HasFlag (MouseFlags.Button4Pressed),
  74. _ => throw new ArgumentOutOfRangeException (nameof (btn))
  75. };
  76. }
  77. }