Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Terminal.Gui/Input/Keyboard/Key.cs
Original file line number Diff line number Diff line change
Expand Up @@ -692,11 +692,16 @@ public bool TryGetPrintableRune (out Rune rune)
public static implicit operator string (Key key) => key.ToString ();

/// <inheritdoc/>
/// <remarks>
/// Two <see cref="Key"/> instances are considered equal when their <see cref="KeyCode"/> values match.
/// <see cref="Handled"/> is per-event state and is intentionally excluded from identity so that
/// <see cref="Equals(object?)"/> remains consistent with <see cref="GetHashCode"/>.
/// </remarks>
public override bool Equals (object? obj)
{
if (obj is Key other)
{
return other._keyCode == _keyCode && other.Handled == Handled;
return other._keyCode == _keyCode;
}

return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Claude - Opus 4.7
using System.Collections.Concurrent;

namespace InputTests;

public class KeyEqualityTests
{
[Fact]
public void Equals_ReturnsTrue_WhenHandledDiffers ()
{
Key a = new (KeyCode.F1) { Handled = false };
Key b = new (KeyCode.F1) { Handled = true };

Assert.True (a.Equals (b));
}

[Fact]
public void GetHashCode_IsEqual_WhenHandledDiffers ()
{
Key a = new (KeyCode.F1) { Handled = false };
Key b = new (KeyCode.F1) { Handled = true };

Assert.Equal (a.GetHashCode (), b.GetHashCode ());
}

[Fact]
public void ConcurrentDictionary_Lookup_Succeeds_WhenHandledDiffers ()
{
// Regression test for issue #5170: KeyBindings is a ConcurrentDictionary<Key, KeyBinding>
// and lookup must succeed when the lookup Key has a different Handled value than the stored Key.
ConcurrentDictionary<Key, string> bindings = new ();
Key a = new (KeyCode.F1) { Handled = false };
Key b = new (KeyCode.F1) { Handled = true };
bindings [a] = "binding-A";

Assert.True (bindings.TryGetValue (b, out string? found));
Assert.Equal ("binding-A", found);
}
}
9 changes: 5 additions & 4 deletions Tests/UnitTestsParallelizable/Input/Keyboard/KeyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -618,9 +618,9 @@ public void Equals_ShouldReturnTrue_WhenEqual ()
Key b = Key.A;
Assert.True (a.Equals (b));

// Handled is per-event state and not part of Key identity (see issue #5170).
b.Handled = true;
Assert.False (a.Equals (b));

Assert.True (a.Equals (b));
}

[Fact]
Expand All @@ -634,12 +634,13 @@ public void Equals_Handled_Changed_ShouldReturnTrue_WhenEqual ()
}

[Fact]
public void Equals_Handled_Changed_ShouldReturnFalse_WhenNotEqual ()
public void Equals_Handled_Changed_ShouldReturnTrue_WhenHandledDiffers ()
{
// Handled is per-event state and is intentionally excluded from Key identity (see issue #5170).
Key a = Key.A;
a.Handled = true;
Key b = Key.A;
Assert.False (a.Equals (b));
Assert.True (a.Equals (b));
}


Expand Down
Loading