-
Notifications
You must be signed in to change notification settings - Fork 736
Fixes #4471, #4474, #3714, #2588 - MASSIVE: Refactors Mouse Support #4472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
tig
wants to merge
46
commits into
gui-cs:v2_develop
Choose a base branch
from
tig:v2_4471-Continuous
base: v2_develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+10,294
−3,525
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Enhanced logging across multiple classes to improve observability: - Added debug log for `OperationCanceledException` in `MainLoopCoordinator<TInputRecord>`. - Logged mouse event details in `MouseImpl` for better event tracking. - Added trace log in `InputImpl<TInputRecord>` to indicate input availability. - Replaced `LogInformation` with `Logging.Information` in `WindowsInput`. - Logged detailed error information for console input failures in `WindowsInput`. These changes enhance maintainability and debugging capabilities.
continuous actions like auto-scrolling. Enhanced `IMouseHeldDown` to include richer event data and updated `Start` to accept `MouseEventArgs`. Removed `MouseGrabHandler` and integrated its functionality into `MouseHeldDown` and `MouseImpl`. Streamlined mouse event handling in `View` by introducing lazy instantiation of `MouseHeldDown` and replacing legacy methods with `RaiseCommandsBoundToButtonClickedFlags` and `RaiseCommandsBoundToWheelFlags`. Removed the `MouseWheel` event and transitioned wheel handling to the command-binding system. Improved `MouseBindings` to convert "pressed" events to "clicked" events for better command invocation. Updated `TimedEvents` to ensure proper handling of scheduled timeouts. Refactored `MouseTests` to align with the new `MouseHeldDown` implementation. Removed redundant code in `Button` and performed general cleanup and documentation updates for better maintainability.
- Introduced semantic aliases for `MouseFlags` to improve readability. - Enhanced XML documentation for `MouseFlags` and related enums. - Refactored `MouseHeldDown` to improve type safety and add detailed logging. - Updated `View.Mouse.cs` to handle mouse events more consistently. - Changed default mouse bindings to use semantic aliases (e.g., `LeftButtonClicked`). - Removed redundant and excessive logging across multiple files. - Updated `Button` class and test cases to align with new mouse flag aliases. - Improved handling of continuous button presses and mouse grab logic.
Introduces a broad suite of new xUnit tests for Terminal.Gui's driver, input, and output subsystems under the DriverTests namespace. Tests cover keyboard mapping, mouse click detection, input processing (including Unicode/surrogate pairs), and output buffer behavior. Includes edge cases for modifiers, wide/combining characters, and mouse event quirks. Some tests document known limitations or are marked as skipped for future investigation. This significantly increases test coverage and documents both expected and legacy behaviors.
Added Timestamp property to MouseEventArgs. Refactored MouseButtonClickTracker and MouseInterpreter to use event timestamps. Updated all test constructors. MouseButtonClickTrackerTests: 17/17 passing. MouseInterpreterExtendedTests: 9/18 passing (9 need deferred-click assertion updates).
Implemented ITestableInput<char> in UnixInput, enabling injection of synthetic keyboard and mouse events for robust unit testing. Overrode EnqueueKeyDownEvent and EnqueueMouseEvent in UnixInputProcessor to inject ANSI sequences for keys and mouse actions. Added comprehensive unit and debug tests for input injection, event sequencing, and ANSI code mapping. Included detailed driver input/output analysis documentation comparing all drivers and their use of native APIs and ANSI infrastructure. These changes greatly improve testability and cross-platform input simulation.
Introduce AnsiKeyboardEncoder and AnsiMouseEncoder utility classes to convert Key and Mouse objects to ANSI escape sequences, enabling round-trip testing and input injection. Refactor UnixInputProcessor to use these encoders, removing legacy conversion methods. Add comprehensive AnsiKeyboardEncoderTests and remove obsolete MouseToAnsiDebugTests. Minor formatting improvements in AnsiKeyboardParser. These changes improve modularity and testability of ANSI input handling.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR goes deep in redesigning and re-implementing the mouse support in Terminal.Gui. It addresses a large number of deep design/legacy flaws. It is a major change that will:
One of the crux changes here is how we deal with multi-click (including repeat). I studied all of the top UI frameworks and how they deal with multi-click and have borrowed the idea of a click count from AppKit/Cocoa. We will still have the ability to have mouse commands bound to e.g.
MouseFlags.LeftButtonDoubleClickbut the underlying system usesmouseEvent.ClickCountto track. This means that apps can have their own logic for dealing with multi-click with the low levelView.MouseEventor by looking in theCommandContext.Fixes
Fixes Mouse support is seriously flawed and needs to be re-engineered #4471
Fixes Duplicate Mouse Click Events on Double-Click #4474
Fixes
MouseEvent/MouseClickcan't be externally controlled - wasSliderdoes not seem to respect click handlers #3714Fixes ProcessButtonClick strips any modifier keys from mouse events #2588
Renames
MouseEventArgstoMousejust likeKeyAdds tons of new unit tests
Problems with Old Design
Problem: Weak definition of models for each stage between Drivers, Application, and View
IDriver/IInputProcessorimplementations work relative to ANSI (the preferred model that only WindowsDriver breaks).MouseImpl) is unclearProblem: Confusing logic to convert
Pressed→Clickedin multiple placesCurrent Behavior:
PressedandReleasedPressed→Clickedbefore binding lookupProblem: Applications manually track double-click timing
Problem: Lexicon & Taxonomy is Inconsistent and Confusing
MouseEventArgsis borrowed fromSystem.Consolebut is different. It should be named something distinctive. I like the simplicity ofKeyand will renameMouseEventArgstoMouse.Button3Pressedect makes devs work too hard to remember which button is which. The names in theMouseFlagsenums came from Windows. All modern frameworks use real names likeRightButtonPressed. All these will be renamed.HighlightStates,WantContinousButtonPress, andWantMousePositionReportsare too long and don't really convey purpose (esp with new design).MouseButtonStateExare poorly and confusingly named.Design
This describes the new design.
Mouse Flow Summary
TL;DR - The Pipeline
Stage Summary
ESC[<0;10;5MMouse{Pressed, Screen(9,4)}Button code → MouseFlags
Mouse{Clicked, Screen(9,4)}Timing → DoubleClicked
Mouse{Clicked, Viewport(2,1)}Find target view
Handle grab
ViewsUnderMouse
Grab/Ungrab
MouseState updates
MouseGrabView
Accept → Accepting
Key Concepts
Coordinates
ESC[<0;10;5MScreenPosition = (9,4)Position = (2,1)Mouse Flags
LeftButtonPressed,LeftButtonReleasedLeftButtonClicked,LeftButtonDoubleClickedCommands
ActivateAcceptMouse Grab
When: View has
MouseHighlightStatesorMouseHoldRepeatLifecycle:
MouseState |= PressedMouseState |= PressedOutside(unlessWantContinuous)Grabbed View Receives:
mouse.Viewset to grabbed viewKey Design Principles:
Complete Behavior Matrix
Normal Button (MouseHoldRepeat = false)
PressedRelease:
Unpressed111Release(2):
21Release(2):
2Release(3):
3Key Point: Each release fires Accept. ClickCount tracks which click in the sequence.
Repeat Button (MouseHoldRepeat = true)
PressedRelease:
Unpressed11SmoothAcceleratingTimeout)1Release(2):
21,2,3Quick click: one release
1(repeated)Click:
1or2Key Point: Timer fires Accept repeatedly with ClickCount=1. Quick releases also fire Accept with appropriate ClickCount.
Mouse Event Flow (Complete Pipeline)
Stage 1: ANSI Input → AnsiMouseParser
Stage 2: MouseInterpreter (Click Synthesis + ClickCount)
Single Click:
Double Click:
Triple Click:
Key Behaviors:
Stage 3: MouseImpl (Routing & Grab)
Stage 4: View.NewMouseEvent (Visual State + Commands)
For Views with MouseHighlightStates:
For Views with MouseHoldRepeat:
Default MouseBindings
View Base Class (All Views)
Button Class
ListView Class (Example of Custom Handling)
MouseState vs ClickCount vs Commands
Three Independent Concerns
Relationships
Example: Button with
MouseHighlightStates = MouseState.PressedMouseHoldRepeat Deep Dive
Timer Behavior
ClickCount Interaction
Hold for 2+ seconds:
Double-click quickly:
Key Insight: Timer and multi-click are independent. Timer repeats with ClickCount=1 until release. Quick clicks don't trigger timer but still track ClickCount.