• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orion-ecs / keen-eye / 20767041456

07 Jan 2026 12:58AM UTC coverage: 87.804% (+17.6%) from 70.212%
20767041456

push

github

tyevco
fix: Resolve all SonarAnalyzer errors for clean build

Fix all analyzer violations to achieve 0 errors, 0 warnings with
SonarAnalyzer.CSharp v10.17.0 and TreatWarningsAsErrors enabled.

Key fixes:
- S2325: Make methods static where appropriate
- S1066: Merge nested if statements
- S1481: Replace unused variables with discards
- S127: Refactor for loops to while loops in CLI arg parsing
- S3218: Rename properties that shadow System types
- S3878: Suppress where conflicting with S3220 (params array)
- S3904: Suppress for SDK projects (no assembly output)
- S3881: Implement proper IDisposable pattern
- S2292: Convert to auto-implemented properties
- IDE0059: Remove unnecessary variable assignments

Also updates test files to use static method calls after
refactoring instance methods to static.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

8869 of 11773 branches covered (75.33%)

Branch coverage included in aggregate %.

639 of 867 new or added lines in 131 files covered. (73.7%)

15 existing lines in 11 files now uncovered.

155014 of 174874 relevant lines covered (88.64%)

1.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.88
/src/KeenEyes.UI/Systems/UIInputSystem.cs
1
using System.Numerics;
2
using KeenEyes.Input.Abstractions;
3
using KeenEyes.UI.Abstractions;
4

5
namespace KeenEyes.UI;
6

7
/// <summary>
8
/// System that processes input events and updates UI interaction states.
9
/// </summary>
10
/// <remarks>
11
/// <para>
12
/// The input system performs hit testing to determine which UI element is under the cursor,
13
/// updates hover/pressed states on <see cref="UIInteractable"/> components, and fires
14
/// appropriate events.
15
/// </para>
16
/// <para>
17
/// This system should run in <see cref="SystemPhase.EarlyUpdate"/> phase to process
18
/// input before other systems.
19
/// </para>
20
/// </remarks>
21
public sealed class UIInputSystem : SystemBase
22
{
23
    private UIHitTester? hitTester;
24
    private UIContext? uiContext;
25
    private IInputContext? inputContext;
26
    private Entity hoveredEntity = Entity.Null;
1✔
27
    private Entity pressedEntity = Entity.Null;
1✔
28
    private Vector2 dragStartPosition;
29
    private Vector2 lastDragPosition;
30
    private bool isDragging;
31
    private double lastClickTime;
32
    private const double DoubleClickTime = 0.3; // seconds
33

34
    /// <inheritdoc />
35
    protected override void OnInitialize()
36
    {
37
        hitTester = new UIHitTester(World);
1✔
38
    }
1✔
39

40
    /// <inheritdoc />
41
    protected override void OnBeforeUpdate(float deltaTime)
42
    {
43
        // Clear pending events from previous frame
44
        foreach (var entity in World.Query<UIInteractable>())
×
45
        {
46
            ref var interactable = ref World.Get<UIInteractable>(entity);
×
NEW
47
            interactable.PendingEvents = UIEventType.None;
×
48
        }
49
    }
×
50

51
    /// <inheritdoc />
52
    public override void Update(float deltaTime)
53
    {
54
        // Lazy initialization
55
        if (inputContext is null && !World.TryGetExtension(out inputContext))
1✔
56
        {
57
            return;
1✔
58
        }
59

60
        if (uiContext is null && !World.TryGetExtension(out uiContext))
1✔
61
        {
62
            return;
1✔
63
        }
64

65
        if (hitTester is null)
1✔
66
        {
67
            return;
×
68
        }
69

70
        // Local copies for null safety - fields are verified non-null above
71
        var input = inputContext!;
1✔
72
        var mouse = input.Mouse;
1✔
73
        var mousePos = mouse.Position;
1✔
74

75
        // Hit test
76
        var hitEntity = hitTester.HitTest(mousePos);
1✔
77

78
        // Handle hover changes
79
        ProcessHover(hitEntity, mousePos);
1✔
80

81
        // Handle mouse button input
82
        ProcessMouseInput(mouse, mousePos, hitEntity);
1✔
83
    }
1✔
84

85
    private void ProcessHover(Entity hitEntity, Vector2 mousePos)
86
    {
87
        // Hover exit
88
        if (hoveredEntity.IsValid &&
1✔
89
            hoveredEntity != hitEntity &&
1✔
90
            World.IsAlive(hoveredEntity) &&
1✔
91
            World.Has<UIInteractable>(hoveredEntity))
1✔
92
        {
93
            ref var interactable = ref World.Get<UIInteractable>(hoveredEntity);
1✔
94
            interactable.State &= ~UIInteractionState.Hovered;
1✔
95
            interactable.PendingEvents |= UIEventType.PointerExit;
1✔
96

97
            World.Send(new UIPointerExitEvent(hoveredEntity));
1✔
98
        }
99

100
        // Hover enter
101
        if (hitEntity.IsValid &&
1✔
102
            hitEntity != hoveredEntity &&
1✔
103
            World.Has<UIInteractable>(hitEntity))
1✔
104
        {
105
            ref var interactable = ref World.Get<UIInteractable>(hitEntity);
1✔
106
            interactable.State |= UIInteractionState.Hovered;
1✔
107
            interactable.PendingEvents |= UIEventType.PointerEnter;
1✔
108

109
            World.Send(new UIPointerEnterEvent(hitEntity, mousePos));
1✔
110
        }
111

112
        hoveredEntity = hitEntity;
1✔
113
    }
1✔
114

115
    private void ProcessMouseInput(IMouse mouse, Vector2 mousePos, Entity hitEntity)
116
    {
117
        // Check for mouse button down
118
        if (mouse.IsButtonDown(MouseButton.Left))
1✔
119
        {
120
            if (!pressedEntity.IsValid && hitEntity.IsValid && World.Has<UIInteractable>(hitEntity))
1✔
121
            {
122
                ref var interactable = ref World.Get<UIInteractable>(hitEntity);
1✔
123

124
                if (interactable.CanClick || interactable.CanDrag)
1✔
125
                {
126
                    pressedEntity = hitEntity;
1✔
127
                    interactable.State |= UIInteractionState.Pressed;
1✔
128
                    interactable.PendingEvents |= UIEventType.PointerDown;
1✔
129
                    dragStartPosition = mousePos;
1✔
130
                    lastDragPosition = mousePos;
1✔
131

132
                    // Request focus if element is focusable
133
                    if (interactable.CanFocus && uiContext is not null)
1✔
134
                    {
135
                        uiContext.RequestFocus(hitEntity);
1✔
136
                    }
137
                }
138
            }
139

140
            // Handle dragging
141
            if (pressedEntity.IsValid && World.Has<UIInteractable>(pressedEntity))
1✔
142
            {
143
                ref var interactable = ref World.Get<UIInteractable>(pressedEntity);
1✔
144

145
                if (interactable.CanDrag && !isDragging)
1✔
146
                {
147
                    // Start drag if moved enough
148
                    var delta = mousePos - dragStartPosition;
1✔
149
                    if (delta.LengthSquared() > 25) // 5 pixel threshold squared
1✔
150
                    {
151
                        isDragging = true;
1✔
152
                        interactable.State |= UIInteractionState.Dragging;
1✔
153
                        interactable.PendingEvents |= UIEventType.DragStart;
1✔
154

155
                        World.Send(new UIDragStartEvent(pressedEntity, dragStartPosition));
1✔
156
                    }
157
                }
158

159
                if (isDragging)
1✔
160
                {
161
                    var delta = mousePos - lastDragPosition;
1✔
162
                    lastDragPosition = mousePos;
1✔
163
                    World.Send(new UIDragEvent(pressedEntity, mousePos, delta));
1✔
164
                }
165
            }
166
        }
167
        else
168
        {
169
            // Mouse button released
170
            if (pressedEntity.IsValid && World.IsAlive(pressedEntity) && World.Has<UIInteractable>(pressedEntity))
1✔
171
            {
172
                ref var interactable = ref World.Get<UIInteractable>(pressedEntity);
1✔
173
                interactable.State &= ~UIInteractionState.Pressed;
1✔
174
                interactable.PendingEvents |= UIEventType.PointerUp;
1✔
175

176
                if (isDragging)
1✔
177
                {
178
                    // End drag
179
                    interactable.State &= ~UIInteractionState.Dragging;
1✔
180
                    interactable.PendingEvents |= UIEventType.DragEnd;
1✔
181
                    isDragging = false;
1✔
182

183
                    World.Send(new UIDragEndEvent(pressedEntity, mousePos));
1✔
184
                }
185
                else if (interactable.CanClick && pressedEntity == hitEntity)
1✔
186
                {
187
                    // Click occurred
188
                    interactable.PendingEvents |= UIEventType.Click;
1✔
189

190
                    // Check for double-click
191
                    var currentTime = Environment.TickCount / 1000.0;
1✔
192
                    if (currentTime - lastClickTime < DoubleClickTime)
1✔
193
                    {
194
                        interactable.PendingEvents |= UIEventType.DoubleClick;
1✔
195
                    }
196
                    lastClickTime = currentTime;
1✔
197

198
                    World.Send(new UIClickEvent(pressedEntity, mousePos, MouseButton.Left));
1✔
199
                }
200
            }
201

202
            pressedEntity = Entity.Null;
1✔
203
        }
204
    }
1✔
205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc