using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
///
/// Describes full key gesture or part of a key gesture
///
/// This class is is designed to react to key events even it descibes only part of them
/// For example if event argument holds modifiers Ctrl, Shift and key C then partial template
/// with single modifier Ctrl and a key C will match this event
///
[TypeConverter(typeof(PartialKeyGestureConverter))]
public class PartialKeyGesture : KeyGesture
{
private readonly Key _key;
private readonly ModifierKeys _modifiers;
///
/// Key associated with partial key gesture
///
public new Key Key
{
get
{
return _key;
}
}
///
/// Modifier keys associated with partial key gesture
///
public new ModifierKeys Modifiers
{
get
{
return _modifiers;
}
}
///
/// Create new instance of from
///
/// Arguments generated by key event
public PartialKeyGesture(KeyEventArgs keyEventArgs)
: base(Key.None, ModifierKeys.None)
{
var keyboardDevice = (KeyboardDevice)keyEventArgs.Device;
var enteredKey = keyEventArgs.Key == Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key;
var enteredModifiers = keyboardDevice.Modifiers;
if(Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt,
Key.LeftShift, Key.RightShift,
Key.LeftCtrl, Key.RightCtrl,
Key.LWin, Key.RWin}, enteredKey) >= 0) {
_key = Key.None;
_modifiers = enteredModifiers;
} else {
_key = enteredKey;
_modifiers = enteredModifiers;
}
}
///
/// Create new instance of from
///
/// Key gesture
public PartialKeyGesture(KeyGesture gesture)
: base(Key.None, ModifierKeys.None)
{
var partialKeyGesture = gesture as PartialKeyGesture;
if (partialKeyGesture != null) {
_key = partialKeyGesture.Key;
_modifiers = partialKeyGesture.Modifiers;
} else if (gesture is MultiKeyGesture) {
throw new ArgumentException("Can not create partial key gesture from multi-key gesture");
} else {
_key = gesture.Key;
_modifiers = gesture.Modifiers;
}
}
///
/// Create new instance of having key and modifiers
///
/// The key associated with partial key gesture
/// Modifier keys associated with partial key gesture
public PartialKeyGesture(Key key, ModifierKeys modifiers)
: base(Key.None, ModifierKeys.None)
{
_key = key;
_modifiers = modifiers;
}
///
/// Create new instance of having only key and no modifiers
///
/// The key associated with partial key gesture
public PartialKeyGesture(Key key)
: base(Key.None, ModifierKeys.None)
{
_key = key;
_modifiers = ModifierKeys.None;
}
///
/// Create new instance of having only key and no modifiers
///
/// Modifier keys associated with partial key gesture
public PartialKeyGesture(ModifierKeys modifiers)
: base(Key.None, ModifierKeys.None)
{
_key = Key.None;
_modifiers = modifiers;
}
///
/// Determines whether key gesture strictly matches this key gesture template
/// (That is key and modifier both match key event arguments)
///
/// The target
/// Input event arguments
/// True if the event data matches this ; otherwise, false.
public bool StrictlyMatches(object targetElement, InputEventArgs args)
{
var keyEventArgs = args as KeyEventArgs;
if(keyEventArgs == null)
{
return false;
}
var keyboard = (KeyboardDevice)keyEventArgs.Device;
// If system key is pressed
if (keyEventArgs.Key == Key.System)
{
return keyboard.Modifiers == Modifiers && keyEventArgs.SystemKey == Key;
}
return keyboard.Modifiers == Modifiers && keyEventArgs.Key == Key;
}
///
/// Determines whether key event arguments matches this instance of
///
/// The target
/// Input event arguments
/// True if event data matches parial event arguments otherwise false
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
var keyEventArgs = inputEventArgs as KeyEventArgs;
if(keyEventArgs == null)
{
return false;
}
var keyboard = (KeyboardDevice)keyEventArgs.Device;
// When system key (Alt) is pressed real key is moved to SystemKey property
var enteredKey = keyEventArgs.Key == Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key;
var keyMatches = Key == enteredKey;
// Determine whether template contains only part of modifier keys contained in
// gesture. For example if template contains Control modifier, but gesture contains
// Control and Alt true will be returned
var modifierMatches = keyboard.Modifiers - (keyboard.Modifiers ^ Modifiers) >= 0;
// Template contains no modifiers compare only keys
if (Modifiers == ModifierKeys.None)
{
return keyMatches;
}
// If template has modifiers but key is one of modifier keys return true if
// modifiers match. This is used because when user presses modifier key it is
// presented in Key property and Modifiers property
if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt,
Key.LeftShift, Key.RightShift,
Key.LeftCtrl, Key.RightCtrl,
Key.LWin, Key.RWin,
Key.System}, enteredKey) >= 0)
{
return modifierMatches;
}
return modifierMatches && keyMatches;
}
///
/// Returns string that represents
///
/// String
public override string ToString()
{
var pressedButton = new StringBuilder();
if (Modifiers != ModifierKeys.None)
{
pressedButton.AppendFormat("{0}+", new ModifierKeysConverter().ConvertToInvariantString(Modifiers));
}
// Filter modifier keys from being displayed twice (example: Ctrl + LeftCtrl)
if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt,
Key.LeftShift, Key.RightShift,
Key.LeftCtrl, Key.RightCtrl,
Key.LWin, Key.RWin,
Key.System}, Key) < 0)
{
pressedButton.Append(new KeyConverter().ConvertToInvariantString(Key));
}
return pressedButton.ToString();
}
}
}