| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using Avalonia.Utilities;
- namespace Avalonia.Input
- {
- /// <summary>
- /// Defines a keyboard input combination.
- /// </summary>
- public sealed class KeyGesture : IEquatable<KeyGesture>
- {
- private static readonly Dictionary<string, Key> s_keySynonyms = new Dictionary<string, Key>
- {
- { "+", Key.OemPlus }, { "-", Key.OemMinus }, { ".", Key.OemPeriod }, { ",", Key.OemComma }
- };
- public KeyGesture(Key key, KeyModifiers modifiers = KeyModifiers.None)
- {
- Key = key;
- KeyModifiers = modifiers;
- }
- public bool Equals(KeyGesture? other)
- {
- if (ReferenceEquals(null, other)) return false;
- if (ReferenceEquals(this, other)) return true;
- return Key == other.Key && KeyModifiers == other.KeyModifiers;
- }
- public override bool Equals(object? obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- return obj is KeyGesture gesture && Equals(gesture);
- }
- public override int GetHashCode()
- {
- unchecked
- {
- return ((int)Key * 397) ^ (int)KeyModifiers;
- }
- }
- 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; }
-
- public KeyModifiers KeyModifiers { get; }
- public static KeyGesture Parse(string gesture)
- {
- // string.Split can't be used here because "Ctrl++" is a perfectly valid key gesture
- var key = Key.None;
- var keyModifiers = KeyModifiers.None;
- var cstart = 0;
- for (var c = 0; c <= gesture.Length; c++)
- {
- var ch = c == gesture.Length ? '\0' : gesture[c];
- bool isLast = c == gesture.Length;
- if (isLast || (ch == '+' && cstart != c))
- {
- var partSpan = gesture.AsSpan(cstart, c - cstart).Trim();
- if (isLast)
- {
- key = ParseKey(partSpan.ToString());
- }
- else
- {
- keyModifiers |= ParseModifier(partSpan);
- }
- cstart = c + 1;
- }
- }
- return new KeyGesture(key, keyModifiers);
- }
- public override string ToString()
- {
- var s = StringBuilderCache.Acquire();
- static void Plus(StringBuilder s)
- {
- if (s.Length > 0)
- {
- s.Append("+");
- }
- }
- if (KeyModifiers.HasAllFlags(KeyModifiers.Control))
- {
- s.Append("Ctrl");
- }
- if (KeyModifiers.HasAllFlags(KeyModifiers.Shift))
- {
- Plus(s);
- s.Append("Shift");
- }
- if (KeyModifiers.HasAllFlags(KeyModifiers.Alt))
- {
- Plus(s);
- s.Append("Alt");
- }
- if (KeyModifiers.HasAllFlags(KeyModifiers.Meta))
- {
- Plus(s);
- s.Append("Cmd");
- }
- Plus(s);
- s.Append(Key);
- return StringBuilderCache.GetStringAndRelease(s);
- }
- public bool Matches(KeyEventArgs keyEvent) =>
- keyEvent != null &&
- keyEvent.KeyModifiers == KeyModifiers &&
- ResolveNumPadOperationKey(keyEvent.Key) == ResolveNumPadOperationKey(Key);
- // 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 EnumHelper.Parse<Key>(key, true);
- }
- private static KeyModifiers ParseModifier(ReadOnlySpan<char> modifier)
- {
- if (modifier.Equals("ctrl".AsSpan(), StringComparison.OrdinalIgnoreCase))
- {
- return KeyModifiers.Control;
- }
- if (modifier.Equals("cmd".AsSpan(), StringComparison.OrdinalIgnoreCase) ||
- modifier.Equals("win".AsSpan(), StringComparison.OrdinalIgnoreCase) ||
- modifier.Equals("⌘".AsSpan(), StringComparison.OrdinalIgnoreCase))
- {
- return KeyModifiers.Meta;
- }
- return EnumHelper.Parse<KeyModifiers>(modifier.ToString(), true);
- }
- private Key ResolveNumPadOperationKey(Key key)
- {
- switch (key)
- {
- case Key.Add:
- return Key.OemPlus;
- case Key.Subtract:
- return Key.OemMinus;
- case Key.Decimal:
- return Key.OemPeriod;
- default:
- return key;
- }
- }
- }
- }
|