12 changed files with 243 additions and 0 deletions
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using System.Globalization; |
|||
using OmniXaml.TypeConversion; |
|||
using Perspex.Input; |
|||
|
|||
namespace Perspex.Markup.Xaml.Converters |
|||
{ |
|||
class KeyGestureConverter : ITypeConverter |
|||
{ |
|||
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) |
|||
{ |
|||
return sourceType == typeof(string); |
|||
} |
|||
|
|||
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) |
|||
{ |
|||
return KeyGesture.Parse((string)value); |
|||
} |
|||
|
|||
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Windows.Input; |
|||
|
|||
namespace Perspex.Input |
|||
{ |
|||
public class KeyBinding : PerspexObject |
|||
{ |
|||
public static PerspexProperty<ICommand> CommandProperty = |
|||
PerspexProperty.Register<KeyBinding, ICommand>("Command"); |
|||
|
|||
public ICommand Command |
|||
{ |
|||
get { return GetValue(CommandProperty); } |
|||
set { SetValue(CommandProperty, value); } |
|||
} |
|||
|
|||
public static PerspexProperty<KeyGesture> GestureProperty = |
|||
PerspexProperty.Register<KeyBinding, KeyGesture>("Gesture"); |
|||
|
|||
public KeyGesture Gesture |
|||
{ |
|||
get { return GetValue(GestureProperty); } |
|||
set { SetValue(GestureProperty, value); } |
|||
} |
|||
|
|||
public void TryHandle(KeyEventArgs args) |
|||
{ |
|||
if (Gesture?.Matches(args) == true) |
|||
{ |
|||
args.Handled = true; |
|||
if (Command?.CanExecute(null) == true) |
|||
Command.Execute(null); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Perspex.Input |
|||
{ |
|||
public sealed class KeyGesture : IEquatable<KeyGesture> |
|||
{ |
|||
public bool Equals(KeyGesture other) |
|||
{ |
|||
if (ReferenceEquals(null, other)) return false; |
|||
if (ReferenceEquals(this, other)) return true; |
|||
return Key == other.Key && Modifiers == other.Modifiers; |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (ReferenceEquals(null, obj)) return false; |
|||
if (ReferenceEquals(this, obj)) return true; |
|||
return obj is KeyGesture && Equals((KeyGesture) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
return ((int) Key*397) ^ (int) Modifiers; |
|||
} |
|||
} |
|||
|
|||
public static bool operator ==(KeyGesture left, KeyGesture right) |
|||
{ |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(KeyGesture left, KeyGesture right) |
|||
{ |
|||
return !Equals(left, right); |
|||
} |
|||
|
|||
public Key Key { get; set; } |
|||
|
|||
public InputModifiers Modifiers { get; set; } |
|||
|
|||
|
|||
static Dictionary<string, Key> KeySynonims = 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 (KeySynonims.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) |
|||
{ |
|||
//string.Split can't be used here because "Ctrl++" is a perfectly valid key gesture
|
|||
|
|||
var parts = new List<string>(); |
|||
|
|||
var cstart = 0; |
|||
for (var c = 0; c <= gesture.Length; c++) |
|||
{ |
|||
var ch = c == gesture.Length ? '\0' : gesture[c]; |
|||
if (c == gesture.Length || (ch == '+' && cstart != c)) |
|||
{ |
|||
parts.Add(gesture.Substring(cstart, c - cstart)); |
|||
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++) |
|||
{ |
|||
if (c == parts.Count - 1) |
|||
rv.Key = ParseKey(parts[c]); |
|||
else |
|||
rv.Modifiers |= ParseModifier(parts[c]); |
|||
} |
|||
return rv; |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
var parts = new List<string>(); |
|||
foreach (var flag in Enum.GetValues(typeof (InputModifiers)).Cast<InputModifiers>()) |
|||
{ |
|||
if (Modifiers.HasFlag(flag) && flag != InputModifiers.None) |
|||
parts.Add(flag.ToString()); |
|||
} |
|||
parts.Add(Key.ToString()); |
|||
return string.Join(" + ", parts); |
|||
} |
|||
|
|||
public bool Matches(KeyEventArgs keyEvent) => keyEvent.Key == Key && keyEvent.Modifiers == Modifiers; |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Xunit; |
|||
|
|||
namespace Perspex.Input.UnitTests |
|||
{ |
|||
public class KeyGestureParseTests |
|||
{ |
|||
private static readonly Dictionary<string, KeyGesture> SampleData = new Dictionary<string, KeyGesture> |
|||
{ |
|||
{"Ctrl+A", new KeyGesture {Key = Key.A, Modifiers = InputModifiers.Control}}, |
|||
{" \tShift\t+Alt +B", new KeyGesture {Key = Key.B, Modifiers = InputModifiers.Shift|InputModifiers.Alt} }, |
|||
{"Control++", new KeyGesture {Key = Key.OemPlus, Modifiers = InputModifiers.Control} } |
|||
}; |
|||
|
|||
|
|||
|
|||
[Fact] |
|||
public void Key_Gesture_Is_Able_To_Parse_Sample_Data() |
|||
{ |
|||
foreach (var d in SampleData) |
|||
Assert.Equal(d.Value, KeyGesture.Parse(d.Key)); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue