Browse Source

Merge branch 'master' into fix-managed-dialog-enumeration

pull/2995/head
danwalmsley 7 years ago
committed by GitHub
parent
commit
e9e51d7f09
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 129
      src/Avalonia.Input/KeyGesture.cs
  2. 4
      tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs
  3. 20
      tests/Avalonia.Input.UnitTests/KeyGestureTests.cs

129
src/Avalonia.Input/KeyGesture.cs

@ -1,41 +1,56 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Avalonia.Input namespace Avalonia.Input
{ {
/// <summary>
/// Defines a keyboard input combination.
/// </summary>
public sealed class KeyGesture : IEquatable<KeyGesture> public sealed class KeyGesture : IEquatable<KeyGesture>
{ {
public KeyGesture() private static readonly Dictionary<string, Key> s_keySynonyms = new Dictionary<string, Key>
{
{ "+", Key.OemPlus }, { "-", Key.OemMinus }, { ".", Key.OemPeriod }
};
[Obsolete("Use constructor taking KeyModifiers")]
public KeyGesture(Key key, InputModifiers modifiers)
{ {
Key = key;
KeyModifiers = (KeyModifiers)(((int)modifiers) & 0xf);
} }
public KeyGesture(Key key, InputModifiers modifiers = InputModifiers.None) public KeyGesture(Key key, KeyModifiers modifiers = KeyModifiers.None)
{ {
Key = key; Key = key;
Modifiers = modifiers; KeyModifiers = modifiers;
} }
public bool Equals(KeyGesture other) public bool Equals(KeyGesture other)
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;
return Key == other.Key && Modifiers == other.Modifiers;
return Key == other.Key && KeyModifiers == other.KeyModifiers;
} }
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true; if (ReferenceEquals(this, obj)) return true;
return obj is KeyGesture && Equals((KeyGesture) obj);
return obj is KeyGesture && Equals((KeyGesture)obj);
} }
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked unchecked
{ {
return ((int) Key*397) ^ (int) Modifiers; return ((int)Key * 397) ^ (int)KeyModifiers;
} }
} }
@ -49,85 +64,85 @@ namespace Avalonia.Input
return !Equals(left, right); return !Equals(left, right);
} }
public Key Key { get; set; } public Key Key { get; }
[Obsolete("Use KeyModifiers")] [Obsolete("Use KeyModifiers")]
public InputModifiers Modifiers public InputModifiers Modifiers => (InputModifiers)KeyModifiers;
{
get => (InputModifiers)KeyModifiers;
set => KeyModifiers = (KeyModifiers)(((int)value) & 0xf);
}
public KeyModifiers KeyModifiers { get; set; }
public KeyModifiers KeyModifiers { get; }
static readonly Dictionary<string, Key> KeySynonyms = new Dictionary<string, Key>
{
{"+", Key.OemPlus },
{"-", Key.OemMinus},
{".", Key.OemPeriod }
};
//TODO: Move that to external key parser
static Key ParseKey(string key)
{
Key rv;
if (KeySynonyms.TryGetValue(key.ToLower(), out rv))
return rv;
return (Key)Enum.Parse(typeof (Key), key, true);
}
static InputModifiers ParseModifier(string modifier)
{
if (modifier.Equals("ctrl", StringComparison.OrdinalIgnoreCase))
return InputModifiers.Control;
return (InputModifiers) Enum.Parse(typeof (InputModifiers), modifier, true);
}
public static KeyGesture Parse(string gesture) public static KeyGesture Parse(string gesture)
{ {
//string.Split can't be used here because "Ctrl++" is a perfectly valid key gesture // string.Split can't be used here because "Ctrl++" is a perfectly valid key gesture
var parts = new List<string>(); var key = Key.None;
var keyModifiers = KeyModifiers.None;
var cstart = 0; var cstart = 0;
for (var c = 0; c <= gesture.Length; c++) for (var c = 0; c <= gesture.Length; c++)
{ {
var ch = c == gesture.Length ? '\0' : gesture[c]; var ch = c == gesture.Length ? '\0' : gesture[c];
if (c == gesture.Length || (ch == '+' && cstart != c)) bool isLast = c == gesture.Length;
if (isLast || (ch == '+' && cstart != c))
{ {
parts.Add(gesture.Substring(cstart, c - cstart)); var partSpan = gesture.AsSpan(cstart, c - cstart).Trim();
if (isLast)
{
key = ParseKey(partSpan.ToString());
}
else
{
keyModifiers |= ParseModifier(partSpan);
}
cstart = c + 1; cstart = c + 1;
} }
} }
for (var c = 0; c < parts.Count; c++)
parts[c] = parts[c].Trim();
var rv = new KeyGesture();
for (var c = 0; c < parts.Count; c++) return new KeyGesture(key, keyModifiers);
{
if (c == parts.Count - 1)
rv.Key = ParseKey(parts[c]);
else
rv.Modifiers |= ParseModifier(parts[c]);
}
return rv;
} }
public override string ToString() public override string ToString()
{ {
var parts = new List<string>(); var parts = new List<string>();
foreach (var flag in Enum.GetValues(typeof (InputModifiers)).Cast<InputModifiers>())
foreach (var flag in Enum.GetValues(typeof(KeyModifiers)).Cast<KeyModifiers>())
{ {
if (Modifiers.HasFlag(flag) && flag != InputModifiers.None) if (KeyModifiers.HasFlag(flag) && flag != KeyModifiers.None)
{
parts.Add(flag.ToString()); parts.Add(flag.ToString());
}
} }
parts.Add(Key.ToString()); parts.Add(Key.ToString());
return string.Join(" + ", parts); return string.Join(" + ", parts);
} }
public bool Matches(KeyEventArgs keyEvent) => ResolveNumPadOperationKey(keyEvent.Key) == Key && keyEvent.Modifiers == Modifiers; public bool Matches(KeyEventArgs keyEvent) => ResolveNumPadOperationKey(keyEvent.Key) == Key && keyEvent.KeyModifiers == KeyModifiers;
// TODO: Move that to external key parser
private static Key ParseKey(string key)
{
if (s_keySynonyms.TryGetValue(key.ToLower(), out Key rv))
return rv;
return (Key)Enum.Parse(typeof(Key), key, true);
}
private static KeyModifiers ParseModifier(ReadOnlySpan<char> modifier)
{
if (modifier.Equals("ctrl".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
return KeyModifiers.Control;
}
return (KeyModifiers)Enum.Parse(typeof(KeyModifiers), modifier.ToString(), true);
}
private Key ResolveNumPadOperationKey(Key key) private Key ResolveNumPadOperationKey(Key key)
{ {

4
tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs

@ -24,8 +24,8 @@ namespace Avalonia.Controls.UnitTests.Utils
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock()) .Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object); .Bind<IStyler>().ToConstant(styler.Object);
var gesture1 = new KeyGesture {Key = Key.A, Modifiers = InputModifiers.Control}; var gesture1 = new KeyGesture(Key.A, InputModifiers.Control);
var gesture2 = new KeyGesture {Key = Key.B, Modifiers = InputModifiers.Control}; var gesture2 = new KeyGesture(Key.B, InputModifiers.Control);
var tl = new Window(); var tl = new Window();
var button = new Button(); var button = new Button();

20
tests/Avalonia.Input.UnitTests/KeyGestureTests.cs

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit; using Xunit;
namespace Avalonia.Input.UnitTests namespace Avalonia.Input.UnitTests
@ -11,13 +7,11 @@ namespace Avalonia.Input.UnitTests
{ {
public static readonly IEnumerable<object[]> SampleData = new object[][] public static readonly IEnumerable<object[]> SampleData = new object[][]
{ {
new object[]{"Ctrl+A", new KeyGesture {Key = Key.A, Modifiers = InputModifiers.Control}}, new object[]{"Ctrl+A", new KeyGesture(Key.A, InputModifiers.Control)},
new object[]{" \tShift\t+Alt +B", new KeyGesture {Key = Key.B, Modifiers = InputModifiers.Shift|InputModifiers.Alt} }, new object[]{" \tShift\t+Alt +B", new KeyGesture(Key.B, InputModifiers.Shift | InputModifiers.Alt) },
new object[]{"Control++", new KeyGesture {Key = Key.OemPlus, Modifiers = InputModifiers.Control} } new object[]{"Control++", new KeyGesture(Key.OemPlus, InputModifiers.Control) }
}; };
[Theory] [Theory]
[MemberData(nameof(SampleData))] [MemberData(nameof(SampleData))]
public void Key_Gesture_Is_Able_To_Parse_Sample_Data(string text, KeyGesture gesture) public void Key_Gesture_Is_Able_To_Parse_Sample_Data(string text, KeyGesture gesture)
@ -31,10 +25,8 @@ namespace Avalonia.Input.UnitTests
[InlineData(Key.OemPeriod, Key.Decimal)] [InlineData(Key.OemPeriod, Key.Decimal)]
public void Key_Gesture_Matches_NumPad_To_Regular_Digit(Key gestureKey, Key pressedKey) public void Key_Gesture_Matches_NumPad_To_Regular_Digit(Key gestureKey, Key pressedKey)
{ {
var keyGesture = new KeyGesture var keyGesture = new KeyGesture(gestureKey);
{
Key = gestureKey
};
Assert.True(keyGesture.Matches(new KeyEventArgs Assert.True(keyGesture.Matches(new KeyEventArgs
{ {
Key = pressedKey Key = pressedKey

Loading…
Cancel
Save