#nullable enable namespace Terminal.Gui; internal class MouseInterpreter { /// /// Function for returning the current time. Use in unit tests to /// ensure repeatable tests. /// public Func Now { get; set; } /// /// How long to wait for a second, third, fourth click after the first before giving up and /// releasing event as a 'click' /// public TimeSpan RepeatedClickThreshold { get; set; } private readonly MouseButtonStateEx [] _buttonStates; public MouseInterpreter ( Func? now = null, TimeSpan? doubleClickThreshold = null ) { Now = now ?? (() => DateTime.Now); RepeatedClickThreshold = doubleClickThreshold ?? TimeSpan.FromMilliseconds (500); _buttonStates = new [] { new MouseButtonStateEx (Now, RepeatedClickThreshold, 0), new MouseButtonStateEx (Now, RepeatedClickThreshold, 1), new MouseButtonStateEx (Now, RepeatedClickThreshold, 2), new MouseButtonStateEx (Now, RepeatedClickThreshold, 3) }; } public IEnumerable Process (MouseEventArgs e) { yield return e; // For each mouse button for (var i = 0; i < 4; i++) { _buttonStates [i].UpdateState (e, out int? numClicks); if (numClicks.HasValue) { yield return RaiseClick (i, numClicks.Value, e); } } } private MouseEventArgs RaiseClick (int button, int numberOfClicks, MouseEventArgs mouseEventArgs) { var newClick = new MouseEventArgs { Handled = false, Flags = ToClicks (button, numberOfClicks), ScreenPosition = mouseEventArgs.ScreenPosition, View = mouseEventArgs.View, Position = mouseEventArgs.Position }; Logging.Trace ($"Raising click event:{newClick.Flags} at screen {newClick.ScreenPosition}"); return newClick; } private MouseFlags ToClicks (int buttonIdx, int numberOfClicks) { if (numberOfClicks == 0) { throw new ArgumentOutOfRangeException (nameof (numberOfClicks), "Zero clicks are not valid."); } return buttonIdx switch { 0 => numberOfClicks switch { 1 => MouseFlags.Button1Clicked, 2 => MouseFlags.Button1DoubleClicked, _ => MouseFlags.Button1TripleClicked }, 1 => numberOfClicks switch { 1 => MouseFlags.Button2Clicked, 2 => MouseFlags.Button2DoubleClicked, _ => MouseFlags.Button2TripleClicked }, 2 => numberOfClicks switch { 1 => MouseFlags.Button3Clicked, 2 => MouseFlags.Button3DoubleClicked, _ => MouseFlags.Button3TripleClicked }, 3 => numberOfClicks switch { 1 => MouseFlags.Button4Clicked, 2 => MouseFlags.Button4DoubleClicked, _ => MouseFlags.Button4TripleClicked }, _ => throw new ArgumentOutOfRangeException (nameof (buttonIdx), "Unsupported button index") }; } }