Browse Source

More documentation and code refactoring

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/shortcuts@4646 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts^2
Sergej Andrejev 16 years ago
parent
commit
41266b4359
  1. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
  2. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  3. 10
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs
  4. 4
      src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs
  5. 1
      src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj
  6. 38
      src/Main/ICSharpCode.Core.Presentation/Input/GestureCompareMode.cs
  7. 26
      src/Main/ICSharpCode.Core.Presentation/Input/InputGestureCollectionExtensions.cs
  8. 286
      src/Main/ICSharpCode.Core.Presentation/Input/InputGestureExtensions.cs
  9. 46
      src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyBinding.cs
  10. 222
      src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGesture.cs
  11. 166
      src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGestureConverter.cs
  12. 45
      src/Main/ICSharpCode.Core.Presentation/Input/ObservableInputGestureCollection.cs
  13. 482
      src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGesture.cs
  14. 226
      src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGestureConverter.cs

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs

@ -73,8 +73,13 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -73,8 +73,13 @@ namespace ICSharpCode.AvalonEdit.Editing
SDCommandManager.RegisterCommandBindingInfo(commandBinding);
}
static CaretNavigationCommandHandler()
private static bool bindingsRegistered;
public static void RegisterBindings()
{
if(bindingsRegistered) return;
bindingsRegistered = true;
ClassWideBindingGroup = new BindingGroup("CaretNavigationCommandHandler");
classWideInputBindingCategory = new InputBindingCategory("/CaretNavigation", "Caret navigation commands");
SDCommandManager.RegisterInputBindingCategory(classWideInputBindingCategory);

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -82,8 +82,13 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -82,8 +82,13 @@ namespace ICSharpCode.AvalonEdit.Editing
SDCommandManager.RegisterCommandBindingInfo(commandBinding);
}
static EditingCommandHandler()
private static bool bindingsRegistered;
public static void RegisterBindings()
{
if(bindingsRegistered) return;
bindingsRegistered = true;
ClassWideBindingGroup = new BindingGroup("EditingCommandHandler");
classWideInputBindingCategory = new InputBindingCategory("/EditingCommands", "Editing commands");
SDCommandManager.RegisterInputBindingCategory(classWideInputBindingCategory);

10
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs

@ -38,12 +38,20 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -38,12 +38,20 @@ namespace ICSharpCode.AvalonEdit.Editing
get; private set;
}
static TextAreaDefaultInputHandler()
private static bool bindingsRegistered;
public static void RegisterBindings()
{
if(bindingsRegistered) return;
bindingsRegistered = true;
ClassWideBindingGroup = new BindingGroup("TextAreaDefaultInputHandler");
AddCommandBinding("ApplicationCommands.Undo", CanExecuteUndo, ExecuteUndo);
AddCommandBinding("ApplicationCommands.Redo", CanExecuteRedo, ExecuteRedo);
CaretNavigationCommandHandler.RegisterBindings();
EditingCommandHandler.RegisterBindings();
}
static void AddCommandBinding(string routedCommandName, CanExecuteRoutedEventHandler canExecuteHandler, ExecutedRoutedEventHandler executedHandler)

4
src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs

@ -76,7 +76,6 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -76,7 +76,6 @@ namespace ICSharpCode.SharpDevelop.Gui
public void Initialize()
{
// Use shortened assembly qualified name to not lose user defined gestures
// when sharp develop is updated
SDCommandManager.DefaultOwnerTypeName = SDCommandManager.GetShortAssemblyQualifiedName(GetType());
@ -101,6 +100,9 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -101,6 +100,9 @@ namespace ICSharpCode.SharpDevelop.Gui
}
}
// Hack: Later on bindings should be created from *.addin file
ICSharpCode.AvalonEdit.Editing.TextAreaDefaultInputHandler.RegisterBindings();
mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath);
toolBars = ToolBarService.CreateToolBars(this, "/SharpDevelop/Workbench/ToolBar");

1
src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj

@ -90,6 +90,7 @@ @@ -90,6 +90,7 @@
<Compile Include="ConditionalSeparator.cs" />
<Compile Include="DropDownButton.cs" />
<Compile Include="GetBitmapExtension.cs" />
<Compile Include="Input\GestureCompareMode.cs" />
<Compile Include="Input\InputGestureCollectionConverter.cs" />
<Compile Include="Input\ObservableInputGestureCollection.cs" />
<Compile Include="IOptionBindingContainer.cs" />

38
src/Main/ICSharpCode.Core.Presentation/Input/GestureCompareMode.cs

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
using System;
using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
public enum GestureCompareMode
{
/// <summary>
/// Match is successfull when all chrods from both instance of <see cref="InputGesture" /> match
/// or all gestures in both instance of <see cref="InputGestureCollections" /> match
/// </summary>
ExactlyMatches,
/// <summary>
/// Match is successfull when two instance of <see cref="InputGesture" /> ar conflicting.
///
/// Either one or another instance starts with the same chors as other one
/// </summary>
Conflicting,
/// <summary>
/// Match is successfull when template <see cref="InputGesture" /> partly matches compared <see cref="InputGesture" />.
/// Template is found in any place within matched gesture
/// </summary>
PartlyMatches,
/// <summary>
/// Match is successfull when examined <see cref="InputGesture" /> starts with the same keys as template
/// </summary>
StartsWith,
/// <summary>
/// Match is successfull when examined <see cref="InputGesture" /> starts with the same complite chords as template
/// </summary>
StartsWithFullChords,
}
}

26
src/Main/ICSharpCode.Core.Presentation/Input/InputGestureCollectionExtensions.cs

@ -6,10 +6,18 @@ using System.Collections; @@ -6,10 +6,18 @@ using System.Collections;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Description of InputGestureCollectionExtensions.
/// Contains utility methods for work with <see cref="InputGestureCollection" />
/// </summary>
public static class InputGestureCollectionExtensions
{
/// <summary>
/// Determines whether any item from first <see cref="InputGestureCollection" /> is qualified as template for
/// any item from second <see cref="InputGestureCollection" /> when examining using specific <see cref="GestureCompareMode" />
/// </summary>
/// <param name="inputGestureTemplateCollection">Collection of examined templates</param>
/// <param name="testedInputGestureCollection">Collection of examined gestures</param>
/// <param name="mode">Additional comparing rules. See <see cref="GestureCompareMode" /> for details</param>
/// <returns><code>true</code> if first collection contains item which can be qualified as template for any item from second collection; otherwise <code>false</code></returns>
public static bool ContainsTemplateForAny(this InputGestureCollection inputGestureTemplateCollection, InputGestureCollection testedInputGestureCollection, GestureCompareMode mode) {
if((inputGestureTemplateCollection == null || inputGestureTemplateCollection.Count == 0) && (testedInputGestureCollection == null || testedInputGestureCollection.Count == 0)) {
return true;
@ -23,7 +31,14 @@ namespace ICSharpCode.Core.Presentation @@ -23,7 +31,14 @@ namespace ICSharpCode.Core.Presentation
return false;
}
/// <summary>
/// Determines whether any item from first <see cref="InputGestureCollection" /> is qualified as template for
/// provided <see cref="InputGesture" /> when examining using specific <see cref="GestureCompareMode" />
/// </summary>
/// <param name="inputGestureTemplateCollection">Collection of examined templates</param>
/// <param name="testedInputGestureCollection">Examined Gesture</param>
/// <param name="mode">Additional comparing rules. See <see cref="GestureCompareMode" /> for details</param>
/// <returns><code>true</code> if collection contains template which match provided <see cref="InputGesture" />; otherwise <code>false</code></returns>
public static bool ContainsTemplateFor(this InputGestureCollection inputGestureTemplateCollection, InputGesture testedGesture, GestureCompareMode mode) {
foreach (InputGesture template in inputGestureTemplateCollection) {
if (template.IsTemplateFor(testedGesture, mode)) {
@ -35,9 +50,12 @@ namespace ICSharpCode.Core.Presentation @@ -35,9 +50,12 @@ namespace ICSharpCode.Core.Presentation
}
/// <summary>
/// Sort key gestures within input gesture collection by length and type
/// Shorter gestures should be first so they could be matched first.
/// Sort bindings in <see cref="InputBindingCollection" /> according to number of chords each <see cref="InputBinding" />
/// contains.
///
/// Bindings associated with gestures having more chords should be on top.
/// </summary>
/// <param name="inputGestureCollection"></param>
public static void SortByChords(this InputBindingCollection inputGestureCollection)
{
ArrayList.Adapter(inputGestureCollection).Sort(new ChordsCountComparer());

286
src/Main/ICSharpCode.Core.Presentation/Input/InputGestureExtensions.cs

@ -1,174 +1,134 @@ @@ -1,174 +1,134 @@
/*
* Created by SharpDevelop.
* User: Administrator
* Date: 6/26/2009
* Time: 1:13 AM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Windows.Input;
using System.Collections.Generic;
namespace ICSharpCode.Core.Presentation
{
public enum GestureCompareMode
{
ExactlyMatches,
Conflicting,
/// <summary>
/// Match is successfull if template gesture partly matches compared geture.
/// Template is found in any place within matched gesture
/// </summary>
PartlyMatches,
PartlyMatchesFullChords,
/// <summary>
/// match is successfull if matched gesture starts with provided template
/// </summary>
StartsWith,
StartsWithFullChords,
}
{
/// <summary>
/// Description of InputGestureExtensions.
/// Contains utility methods for work with <see cref="InputGesture" />
/// </summary>
public static class InputGestureExtensions
{
/// <summary>
/// Returns true whether compared gesture matches input gesture template
/// </summary>
/// <param name="inputGestureTemplate">Input gesture template</param>
/// <param name="inputGesture">Compared input gesture</param>
/// <param name="mode">Match mode</param>
/// <returns>Returns true if template matches compared geture</returns>
public static bool IsTemplateFor(this InputGesture inputGestureTemplate, InputGesture inputGesture, GestureCompareMode mode)
{
if(mode == GestureCompareMode.Conflicting) {
return
inputGestureTemplate.IsTemplateFor(inputGesture, GestureCompareMode.StartsWithFullChords)
|| inputGesture.IsTemplateFor(inputGestureTemplate, GestureCompareMode.StartsWithFullChords);
}
var multiKeyGesture = inputGesture as MultiKeyGesture;
var multiKeyGestureTemplate = inputGestureTemplate as MultiKeyGesture;
var partialKeyGesture = inputGesture as PartialKeyGesture;
var partialKeyGestureTemplate = inputGestureTemplate as PartialKeyGesture;
var keyGesture = inputGesture as KeyGesture;
var keyGestureTemplate = inputGestureTemplate as KeyGesture;
// Create partial key gestures from key gestures
if(multiKeyGesture == null && partialKeyGesture == null && keyGesture != null) {
partialKeyGesture = new PartialKeyGesture(keyGesture);
}
if(multiKeyGestureTemplate == null && partialKeyGestureTemplate == null && keyGestureTemplate != null) {
partialKeyGestureTemplate = new PartialKeyGesture(keyGestureTemplate);
}
// Create multi key gestures from gestures
if(multiKeyGesture == null && partialKeyGesture != null) {
multiKeyGesture = new MultiKeyGesture(new [] { partialKeyGesture });
}
if(multiKeyGestureTemplate == null && partialKeyGestureTemplate != null) {
multiKeyGestureTemplate = new MultiKeyGesture(new [] { partialKeyGestureTemplate });
}
if(multiKeyGesture == null
|| multiKeyGestureTemplate == null
|| multiKeyGesture.Chords == null
|| multiKeyGestureTemplate.Chords == null
|| multiKeyGestureTemplate.Chords.Count == 0
|| multiKeyGesture.Chords.Count == 0
|| (mode == GestureCompareMode.ExactlyMatches && multiKeyGestureTemplate.Chords.Count != multiKeyGesture.Chords.Count)) {
return false;
}
// Stores N previous chords
var previousChords = new LinkedList<PartialKeyGesture>();
// Search whether chord sequece matches template sequenc in any place
foreach (PartialKeyGesture chord in multiKeyGesture.Chords)
{
// Accumulates previous chords
previousChords.AddLast(chord);
if (previousChords.Count > multiKeyGestureTemplate.Chords.Count)
{
previousChords.RemoveFirst();
}
// Only start comparing with template when needed amount of previous chords where collected
if (previousChords.Count == multiKeyGestureTemplate.Chords.Count)
{
var multiKeyGestureTemplateEnumerator = multiKeyGestureTemplate.Chords.GetEnumerator();
var previousChordsEnumerator = previousChords.GetEnumerator();
multiKeyGestureTemplateEnumerator.Reset();
// Compare two chord sequences in a loop
var multiKeyGesturesMatch = true;
var i = 0;
while (previousChordsEnumerator.MoveNext() && multiKeyGestureTemplateEnumerator.MoveNext())
{
var template = multiKeyGestureTemplateEnumerator.Current;
var gesture = previousChordsEnumerator.Current;
if (((mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.PartlyMatches) && i == previousChords.Count - 1)
|| (mode == GestureCompareMode.PartlyMatches && i == 0)) {
if(!(template.Modifiers == (gesture.Modifiers & template.Modifiers) && (template.Key == Key.None || template.Key == gesture.Key))) {
multiKeyGesturesMatch = false;
break;
}
} else if (template.Modifiers != gesture.Modifiers || template.Key != gesture.Key) {
multiKeyGesturesMatch = false;
break;
}
i++;
}
if(multiKeyGesturesMatch)
{
return true;
}
if (mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.StartsWithFullChords)
{
break;
}
}
}
return false;
}
/// <summary>
/// Determines whether this instance of <see cref="InputGesture"/> matches any of provided templates
/// </summary>
/// <param name="thisGesture">This input gesture</param>
/// <param name="inputGestureTemplateCollection">Collection of input gestures templates which (at least one of them) should match this input gesture to return true</param>
/// <param name="mode">Matching mode</param>
/// <returns>True if this gsture matches templates collection, otherwise false</returns>
public static bool IsTemplateForAny(this InputGesture thisGesture, InputGestureCollection inputGestureTemplateCollection, GestureCompareMode mode)
{
foreach (InputGesture gesture in inputGestureTemplateCollection) {
if (thisGesture.IsTemplateFor(gesture, mode))
{
return true;
}
}
return false;
}
/// <summary>
/// Determines whether provided <see cref="InputGesture" /> is qualified as template for
/// another instance of <see cref="InputGesture" /> when examining using specific <see cref="GestureCompareMode" />
/// </summary>
/// <param name="inputGestureTemplate">Examined input gesture template</param>
/// <param name="inputGesture">Examined input gesture</param>
/// <param name="mode">Additional comparing rules. See <see cref="GestureCompareMode" /> for details</param>
/// <returns><code>true</code> if template matches compared geture; otherwise <code>false</code></returns>
public static bool IsTemplateFor(this InputGesture inputGestureTemplate, InputGesture inputGesture, GestureCompareMode mode)
{
if(mode == GestureCompareMode.Conflicting) {
return inputGestureTemplate.IsTemplateFor(inputGesture, GestureCompareMode.StartsWithFullChords) || inputGesture.IsTemplateFor(inputGestureTemplate, GestureCompareMode.StartsWithFullChords);
}
var multiKeyGesture = inputGesture as MultiKeyGesture;
var multiKeyGestureTemplate = inputGestureTemplate as MultiKeyGesture;
var partialKeyGesture = inputGesture as PartialKeyGesture;
var partialKeyGestureTemplate = inputGestureTemplate as PartialKeyGesture;
var keyGesture = inputGesture as KeyGesture;
var keyGestureTemplate = inputGestureTemplate as KeyGesture;
// Create partial key gestures from key gestures
if(multiKeyGesture == null && partialKeyGesture == null && keyGesture != null) {
partialKeyGesture = new PartialKeyGesture(keyGesture);
}
if(multiKeyGestureTemplate == null && partialKeyGestureTemplate == null && keyGestureTemplate != null) {
partialKeyGestureTemplate = new PartialKeyGesture(keyGestureTemplate);
}
// Create multi key gestures from gestures
if(multiKeyGesture == null && partialKeyGesture != null) {
multiKeyGesture = new MultiKeyGesture(new [] { partialKeyGesture });
}
if(multiKeyGestureTemplate == null && partialKeyGestureTemplate != null) {
multiKeyGestureTemplate = new MultiKeyGesture(new [] { partialKeyGestureTemplate });
}
if(multiKeyGesture == null
|| multiKeyGestureTemplate == null
|| multiKeyGesture.Chords == null
|| multiKeyGestureTemplate.Chords == null
|| multiKeyGestureTemplate.Chords.Count == 0
|| multiKeyGesture.Chords.Count == 0
|| (mode == GestureCompareMode.ExactlyMatches && multiKeyGestureTemplate.Chords.Count != multiKeyGesture.Chords.Count)) {
return false;
}
// Stores N previous chords
var previousChords = new LinkedList<PartialKeyGesture>();
// Search whether chord sequece matches template sequenc in any place
foreach (PartialKeyGesture chord in multiKeyGesture.Chords) {
// Accumulates previous chords
previousChords.AddLast(chord);
if (previousChords.Count > multiKeyGestureTemplate.Chords.Count) {
previousChords.RemoveFirst();
}
// Only start comparing with template when needed amount of previous chords where collected
if (previousChords.Count == multiKeyGestureTemplate.Chords.Count) {
var multiKeyGestureTemplateEnumerator = multiKeyGestureTemplate.Chords.GetEnumerator();
var previousChordsEnumerator = previousChords.GetEnumerator();
multiKeyGestureTemplateEnumerator.Reset();
// Compare two chord sequences in a loop
var multiKeyGesturesMatch = true;
var i = 0;
while (previousChordsEnumerator.MoveNext() && multiKeyGestureTemplateEnumerator.MoveNext()) {
var template = multiKeyGestureTemplateEnumerator.Current;
var gesture = previousChordsEnumerator.Current;
if (((mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.PartlyMatches) && i == previousChords.Count - 1)
|| (mode == GestureCompareMode.PartlyMatches && i == 0)) {
if(!(template.Modifiers == (gesture.Modifiers & template.Modifiers) && (template.Key == Key.None || template.Key == gesture.Key))) {
multiKeyGesturesMatch = false;
break;
}
} else if (template.Modifiers != gesture.Modifiers || template.Key != gesture.Key) {
multiKeyGesturesMatch = false;
break;
}
i++;
}
if(multiKeyGesturesMatch) {
return true;
}
if (mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.StartsWithFullChords) {
break;
}
}
}
return false;
}
/// <summary>
/// Determines whether this instance of <see cref="InputGesture"/> qualifies as template for any of examined gestures
/// </summary>
/// <param name="thisGesture">Examined input gesture template</param>
/// <param name="examinedGestures">Collection of examined gestures</param>
/// <param name="mode">Additional comparing rules. See <see cref="GestureCompareMode" /> for details</param>
/// <returns><code>true</code> if template matches one of the compared getures; otherwise <code>false</code></returns>
public static bool IsTemplateForAny(this InputGesture thisGesture, InputGestureCollection examinedGestures, GestureCompareMode mode)
{
foreach (InputGesture gesture in examinedGestures) {
if (thisGesture.IsTemplateFor(gesture, mode)) {
return true;
}
}
return false;
}
}
}

46
src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyBinding.cs

@ -4,27 +4,27 @@ using System.Windows.Input; @@ -4,27 +4,27 @@ using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Represents input binding which can be invoked by <see cref="MultiKeyGesture"/>
/// </summary>
public class MultiKeyBinding : InputBinding
{
/// <summary>
/// Instance of <see cref="MultiKeyGesture"/>
/// </summary>
[TypeConverter(typeof(MultiKeyGestureConverter))]
public override InputGesture Gesture
{
get { return base.Gesture as MultiKeyGesture; }
set
{
if (!(value is MultiKeyGesture))
{
throw new ArgumentException();
}
base.Gesture = value;
}
}
}
/// <summary>
/// Represents input binding which can be invoked by <see cref="MultiKeyGesture"/>
/// </summary>
public class MultiKeyBinding : InputBinding
{
/// <summary>
/// Gets or sets instance of <see cref="MultiKeyGesture"/>
/// </summary>
[TypeConverter(typeof(MultiKeyGestureConverter))]
public override InputGesture Gesture
{
get {
return base.Gesture as MultiKeyGesture;
}
set {
if (!(value is MultiKeyGesture)) {
throw new ArgumentException();
}
base.Gesture = value;
}
}
}
}

222
src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGesture.cs

@ -6,119 +6,113 @@ using System.Windows.Input; @@ -6,119 +6,113 @@ using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Specifies gesture consisting from multiple key gestures
/// </summary>
[TypeConverter(typeof(MultiKeyGestureConverter))]
public class MultiKeyGesture : KeyGesture
{
private static readonly List<MultiKeyGesture> allGestures = new List<MultiKeyGesture>();
// Set sequence indexes of all sequential key gestures to 0
private static void ResetAllGestures()
{
foreach (var gesture in allGestures)
{
gesture.currentGestureIndex = 0;
}
}
private readonly ReadOnlyCollection<PartialKeyGesture> chords;
private int currentGestureIndex;
private DateTime lastGestureInput;
/// <summary>
/// Maximum delay between multi-key gesture chords
/// </summary>
public static TimeSpan DelayBetweenChords
{
get; set;
}
static MultiKeyGesture()
{
/// <summary>
/// Describes gesture containing multiple chords
/// </summary>
[TypeConverter(typeof(MultiKeyGestureConverter))]
public class MultiKeyGesture : KeyGesture
{
private static readonly List<WeakReference> allGestures = new List<WeakReference>();
// Set sequence indexes of all sequential key gestures to 0
private static void ResetAllGestures()
{
foreach (var gestureWrapper in allGestures) {
if(gestureWrapper.Target != null) {
((MultiKeyGesture)gestureWrapper.Target).currentGestureIndex = 0;
}
}
}
private readonly ReadOnlyCollection<PartialKeyGesture> chords;
private int currentGestureIndex;
private DateTime lastGestureInput;
/// <summary>
/// Maximum delay between pressing chords
/// </summary>
public static TimeSpan DelayBetweenChords
{
get; set;
}
static MultiKeyGesture()
{
DelayBetweenChords = TimeSpan.FromSeconds(2);
}
/// <summary>
/// Creates instance of <see cref="MultiKeyGesture"/> from list of partial key gestures
/// </summary>
/// <param name="gestures">Sequence of partial key gestures</param>
public MultiKeyGesture(IList<PartialKeyGesture> gestures)
: base(Key.None, ModifierKeys.None)
{
if(gestures == null || gestures.Count == 0)
{
throw new ArgumentException("Must specify atleast one gesture");
}
this.chords = new ReadOnlyCollection<PartialKeyGesture>(gestures);
allGestures.Add(this);
}
/// <summary>
/// Sequence of partial key gestures which describe this sequential key gesture
/// </summary>
public ICollection<PartialKeyGesture> Chords
{
get
{
return chords;
}
}
/// <summary>
/// Determines whether key event arguments matches this instance of <see cref="MultiKeyGesture"/>
/// </summary>
/// <param name="targetElement">The target</param>
/// <param name="inputEventArgs">Input event arguments</param>
/// <returns>True if the event data matches this <see cref="MultiKeyGesture"/>; otherwise, false. </returns>
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
var keyEventArgs = inputEventArgs as KeyEventArgs;
if (keyEventArgs == null)
{
return false;
}
if (keyEventArgs.IsRepeat)
{
return false;
}
// Checks wheter it is not too long from last match
var isOnTime = (DateTime.Now - lastGestureInput) <= DelayBetweenChords;
// If strict match is on time
var strictMatch = chords[currentGestureIndex].StrictlyMatches(targetElement, inputEventArgs);
if (strictMatch && (currentGestureIndex == 0 || isOnTime))
{
currentGestureIndex++;
lastGestureInput = DateTime.Now;
inputEventArgs.Handled = true;
// Check whether this is last gesture in sequence
if(currentGestureIndex == chords.Count)
{
ResetAllGestures();
return true;
}
return false;
}
// If partial match is on time allow continue without reseting current gesture index
var partialMatch = chords[currentGestureIndex].Matches(targetElement, inputEventArgs);
if (partialMatch && currentGestureIndex > 0 && isOnTime)
{
return false;
}
currentGestureIndex = 0;
return false;
}
}
}
/// <summary>
/// Creates instance of <see cref="MultiKeyGesture"/> from list of partial key gestures
/// </summary>
/// <param name="gestures">Sequence of partial key gestures</param>
public MultiKeyGesture(IList<PartialKeyGesture> gestures)
: base(Key.None, ModifierKeys.None)
{
if(gestures == null || gestures.Count == 0) {
throw new ArgumentException("Must specify atleast one gesture");
}
this.chords = new ReadOnlyCollection<PartialKeyGesture>(gestures);
allGestures.Add(new WeakReference(this));
}
/// <summary>
/// Sequence of partial key gestures which builds this <see cref="MultiKeyGesture" />
/// </summary>
public ICollection<PartialKeyGesture> Chords
{
get {
return chords;
}
}
/// <summary>
/// Determines whether key event arguments matches this instance of <see cref="MultiKeyGesture"/>
/// </summary>
/// <param name="targetElement">The target</param>
/// <param name="inputEventArgs">Input event arguments</param>
/// <returns><code>true</code> if the event data matches this <see cref="MultiKeyGesture"/>; otherwise <code>false</code></returns>
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
var keyEventArgs = inputEventArgs as KeyEventArgs;
if (keyEventArgs == null) {
return false;
}
if (keyEventArgs.IsRepeat) {
return false;
}
// Checks wheter it is not too long from last match
var isOnTime = (DateTime.Now - lastGestureInput) <= DelayBetweenChords;
// If strict match is on time
var strictMatch = chords[currentGestureIndex].StrictlyMatches(targetElement, inputEventArgs);
if (strictMatch && (currentGestureIndex == 0 || isOnTime)) {
currentGestureIndex++;
lastGestureInput = DateTime.Now;
inputEventArgs.Handled = true;
// Check whether this is last gesture in sequence
if(currentGestureIndex == chords.Count) {
ResetAllGestures();
return true;
}
return false;
}
// If partial match is on time allow continue without reseting current gesture index
var partialMatch = chords[currentGestureIndex].Matches(targetElement, inputEventArgs);
if (partialMatch && currentGestureIndex > 0 && isOnTime) {
return false;
}
currentGestureIndex = 0;
return false;
}
}
}

166
src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGestureConverter.cs

@ -6,95 +6,91 @@ using System.Linq; @@ -6,95 +6,91 @@ using System.Linq;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Converts <see cref="MultiKeyGesture"/> instance to and from other types
/// </summary>
public class MultiKeyGestureConverter : TypeConverter
{
private readonly PartialKeyGestureConverter partialKeyGestureConverter = new PartialKeyGestureConverter();
/// <summary>
/// Determines whether object of specified type can be converted to instance of <see cref="MultiKeyGesture"/>
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="sourceType">The type being evaluated for conversion.</param>
/// <returns>True if this converter can perform the operation; otherwise, false.</returns>
/// <summary>
/// Converts <see cref="MultiKeyGesture"/> instance to and from other types
/// </summary>
public class MultiKeyGestureConverter : TypeConverter
{
private readonly PartialKeyGestureConverter partialKeyGestureConverter = new PartialKeyGestureConverter();
/// <summary>
/// Determines whether object of specified type can be converted to instance of <see cref="MultiKeyGesture"/>
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="sourceType">The type being evaluated for conversion.</param>
/// <returns>True if this converter can perform the operation; otherwise, false.</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if(sourceType == typeof(string))
{
return true;
if(sourceType == typeof(string)) {
return true;
}
return base.CanConvertFrom(context, sourceType);
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// Determines whether an instance of <see cref="MultiKeyGesture"/> can be converted to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="destinationType">The type being evaluated for conversion. </param>
/// <returns>True if this converter can perform the operation; otherwise, false. </returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, destinationType);
}
/// <summary>
/// Attempts to convert a <see cref="MultiKeyGesture"/> to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information. </param>
/// <param name="value">The object to convert</param>
/// <param name="destinationType">The type wich instance of <see cref="PartialKeyGesture"/> is being converted to.</param>
/// <returns>The converted object, or an empty string if value is a null reference</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value == null && destinationType == typeof(string))
{
return String.Empty;
}
var MultiKeyGesture = value as MultiKeyGesture;
if (MultiKeyGesture != null && destinationType == typeof(string))
{
var partialKeyGestureStrings = MultiKeyGesture.Chords.Select(gesture => (string)partialKeyGestureConverter.ConvertTo(context, culture, gesture, typeof(string))).ToArray();
var MultiKeyGestureString = string.Join(",", partialKeyGestureStrings);
return MultiKeyGestureString;
}
return base.ConvertFrom(context, culture, value);
}
/// <summary>
/// Attempts to convert the specified object to a <see cref="MultiKeyGesture"/>, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information.</param>
/// <param name="value">The object to convert</param>
/// <returns>The converted object.</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
/// <summary>
/// Determines whether an instance of <see cref="MultiKeyGesture"/> can be converted to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="destinationType">The type being evaluated for conversion. </param>
/// <returns>True if this converter can perform the operation; otherwise, false. </returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
var gestureString = value as string;
if (gestureString != null) {
var keyGestures = new List<PartialKeyGesture>();
var keyGestureStrings = gestureString.Split(',');
foreach (var keyGestureString in keyGestureStrings) {
var partialKeyGesture = (PartialKeyGesture)new PartialKeyGestureConverter().ConvertFrom(context, culture, keyGestureString);
keyGestures.Add(partialKeyGesture);
}
return new MultiKeyGesture(keyGestures);
}
return base.ConvertFrom(context, culture, value);
if (destinationType == typeof(string)) {
return true;
}
return base.CanConvertFrom(context, destinationType);
}
/// <summary>
/// Attempts to convert a <see cref="MultiKeyGesture"/> to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information. </param>
/// <param name="value">The object to convert</param>
/// <param name="destinationType">The type wich instance of <see cref="PartialKeyGesture"/> is being converted to.</param>
/// <returns>The converted object, or an empty string if value is a null reference</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value == null && destinationType == typeof(string)) {
return String.Empty;
}
var MultiKeyGesture = value as MultiKeyGesture;
if (MultiKeyGesture != null && destinationType == typeof(string)) {
var partialKeyGestureStrings = MultiKeyGesture.Chords.Select(gesture => (string)partialKeyGestureConverter.ConvertTo(context, culture, gesture, typeof(string))).ToArray();
var MultiKeyGestureString = string.Join(",", partialKeyGestureStrings);
return MultiKeyGestureString;
}
return base.ConvertFrom(context, culture, value);
}
/// <summary>
/// Attempts to convert the specified object to a <see cref="MultiKeyGesture"/>, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information.</param>
/// <param name="value">The object to convert</param>
/// <returns>The converted object.</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var gestureString = value as string;
if (gestureString != null) {
var keyGestures = new List<PartialKeyGesture>();
var keyGestureStrings = gestureString.Split(',');
foreach (var keyGestureString in keyGestureStrings) {
var partialKeyGesture = (PartialKeyGesture)new PartialKeyGestureConverter().ConvertFrom(context, culture, keyGestureString);
keyGestures.Add(partialKeyGesture);
}
return new MultiKeyGesture(keyGestures);
}
return base.ConvertFrom(context, culture, value);
}
}
}
}

45
src/Main/ICSharpCode.Core.Presentation/Input/ObservableInputGestureCollection.cs

@ -1,9 +1,3 @@ @@ -1,9 +1,3 @@
/*
* Created by SharpDevelop.
* User: Sergej Andrejev
* Date: 7/17/2009
* Time: 8:56 AM
*/
using System;
using System.Collections;
using System.Collections.Generic;
@ -14,33 +8,40 @@ using System.Windows.Input; @@ -14,33 +8,40 @@ using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Description of ObservableInputBindingCollection.
/// Represents observable collection of <see cref="InputGesture" />
/// </summary>
public class ObservableInputGestureCollection : IList<InputGesture>, INotifyCollectionChanged, IEnumerable<InputGesture>, ICollection<InputGesture>
{
private ObservableCollection<InputGesture> observedInputGestures;
/// <summary>
/// Creates new instance of <see cref="ObservableInputGestureCollection" />
/// </summary>
public ObservableInputGestureCollection()
{
observedInputGestures = new ObservableCollection<InputGesture>();
observedInputGestures.CollectionChanged += observedInputGestures_CollectionChanged;
}
/// <inheritdoc />
public void Add(InputGesture item)
{
observedInputGestures.Add(item);
}
/// <inheritdoc />
public void Insert(int index, InputGesture item)
{
observedInputGestures.Insert(index, item);
}
/// <inheritdoc />
public void RemoveAt(int index)
{
observedInputGestures.RemoveAt(index);
}
/// <inheritdoc />
public InputGesture this[int index]
{
get {
@ -51,6 +52,7 @@ namespace ICSharpCode.Core.Presentation @@ -51,6 +52,7 @@ namespace ICSharpCode.Core.Presentation
}
}
/// <inheritdoc />
public bool IsReadOnly
{
get {
@ -58,6 +60,7 @@ namespace ICSharpCode.Core.Presentation @@ -58,6 +60,7 @@ namespace ICSharpCode.Core.Presentation
}
}
/// <inheritdoc />
public int Count
{
get {
@ -65,57 +68,74 @@ namespace ICSharpCode.Core.Presentation @@ -65,57 +68,74 @@ namespace ICSharpCode.Core.Presentation
}
}
/// <inheritdoc />
public bool Remove(InputGesture item)
{
return observedInputGestures.Remove(item);
}
/// <inheritdoc />
public void Clear()
{
observedInputGestures.Clear();
}
/// <inheritdoc />
public bool Contains(InputGesture item)
{
return observedInputGestures.Contains(item);
}
public void AddRange(InputGestureCollection items)
/// <summary>
/// Add all instances from another <see cref="InputGestureCollection" />
/// </summary>
/// <param name="gestures">Collection of gestures</param>
public void AddRange(InputGestureCollection gestures)
{
foreach(InputGesture item in items) {
foreach(InputGesture item in gestures) {
Add(item);
}
}
public void AddRange(IEnumerable<InputGesture> items)
/// <summary>
/// Add all <see cref="InputGesture" /> instances from enumerable collection
/// </summary>
/// <param name="gestures">Collection of gestures</param>
public void AddRange(IEnumerable<InputGesture> gestures)
{
foreach(InputGesture item in items) {
foreach(InputGesture item in gestures) {
Add(item);
}
}
/// <inheritdoc />
public void CopyTo(InputGesture[] array, int arrayIndex)
{
observedInputGestures.CopyTo(array, arrayIndex);
}
/// <inheritdoc />
public IEnumerator<InputGesture> GetEnumerator()
{
return observedInputGestures.GetEnumerator();
}
/// <inheritdoc />
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return observedInputGestures.GetEnumerator();
}
/// <inheritdoc />
public int IndexOf(InputGesture value)
{
return observedInputGestures.IndexOf(value);
}
/// <inheritdoc />
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <inheritdoc />
private void observedInputGestures_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(CollectionChanged != null) {
@ -123,6 +143,9 @@ namespace ICSharpCode.Core.Presentation @@ -123,6 +143,9 @@ namespace ICSharpCode.Core.Presentation
}
}
/// <summary>
/// Gets <see cref="InputGestureCollection" /> containing all items from this observable collection
/// </summary>
public InputGestureCollection InputGesturesCollection
{
get {

482
src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGesture.cs

@ -5,247 +5,243 @@ using System.Windows.Input; @@ -5,247 +5,243 @@ using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// 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
/// </summary>
[TypeConverter(typeof(PartialKeyGestureConverter))]
public class PartialKeyGesture : KeyGesture
{
private readonly Key _key;
private readonly ModifierKeys _modifiers;
/// <summary>
/// Key associated with partial key gesture
/// </summary>
public new Key Key
{
get
{
return _key;
}
}
/// <summary>
/// Modifier keys associated with partial key gesture
/// </summary>
public new ModifierKeys Modifiers
{
get
{
return _modifiers;
}
}
/// <summary>
/// Create new instance of <see cref="PartialKeyGesture"/> from <see cref="KeyEventArgs"/>
/// </summary>
/// <param name="keyEventArgs">Arguments generated by key event</param>
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;
}
}
/// <summary>
/// Create new instance of <see cref="PartialKeyGesture"/> from <see cref="KeyGesture"/>
/// </summary>
/// <param name="gesture">Key gesture</param>
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;
}
}
/// <summary>
/// Create new instance of <see cref="PartialKeyGesture"/> having key and modifiers
/// </summary>
/// <param name="key">The key associated with partial key gesture</param>
/// <param name="modifiers">Modifier keys associated with partial key gesture</param>
public PartialKeyGesture(Key key, ModifierKeys modifiers)
: base(Key.None, ModifierKeys.None)
{
_key = key;
_modifiers = modifiers;
}
/// <summary>
/// Create new instance of<see cref="PartialKeyGesture"/> having only key and no modifiers
/// </summary>
/// <param name="key">The key associated with partial key gesture</param>
public PartialKeyGesture(Key key)
: base(Key.None, ModifierKeys.None)
{
_key = key;
_modifiers = ModifierKeys.None;
}
/// <summary>
/// Create new instance of<see cref="PartialKeyGesture"/> having only key and no modifiers
/// </summary>
/// <param name="modifiers">Modifier keys associated with partial key gesture</param>
public PartialKeyGesture(ModifierKeys modifiers)
: base(Key.None, ModifierKeys.None)
{
_key = Key.None;
_modifiers = modifiers;
}
/// <summary>
/// Determines whether key gesture strictly matches this key gesture template
/// (That is key and modifier both match key event arguments)
/// </summary>
/// <param name="targetElement">The target</param>
/// <param name="args">Input event arguments</param>
/// <returns>True if the event data matches this <see cref="PartialKeyGesture"/>; otherwise, false. </returns>
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;
}
/// <summary>
/// Determines whether key event arguments matches this instance of <see cref="PartialKeyGesture"/>
/// </summary>
/// <param name="targetElement">The target</param>
/// <param name="inputEventArgs">Input event arguments</param>
/// <returns>True if event data matches parial event arguments otherwise false</returns>
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;
}
public bool IsFull
{
get {
if(Key == Key.None) {
return false;
}
// and function keys are valid without modifier
if (Key >= Key.F1 && Key <= Key.F24) {
return true;
}
// Modifiers alone are not valid
if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt,
Key.LeftShift, Key.RightShift,
Key.LeftCtrl, Key.RightCtrl,
Key.LWin, Key.RWin,
Key.System}, Key) > -1) {
return false;
}
// All other gestures must have modifier (except shift alone because it would mean uppercase)
if((Modifiers & (ModifierKeys.Windows | ModifierKeys.Control | ModifierKeys.Alt)) != ModifierKeys.None) {
return true;
}
return false;
}
}
/// <summary>
/// Returns string that represents <see cref="PartialKeyGesture"/>
/// </summary>
/// <returns>String</returns>
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();
}
}
/// <summary>
/// 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
/// </summary>
[TypeConverter(typeof(PartialKeyGestureConverter))]
public class PartialKeyGesture : KeyGesture
{
private readonly Key _key;
private readonly ModifierKeys _modifiers;
/// <summary>
/// Gets key associated with partial key gesture
/// </summary>
public new Key Key
{
get {
return _key;
}
}
/// <summary>
/// Gets modifier keys associated with partial key gesture
/// </summary>
public new ModifierKeys Modifiers
{
get {
return _modifiers;
}
}
/// <summary>
/// Create new instance of <see cref="PartialKeyGesture"/> from <see cref="KeyEventArgs"/>
/// </summary>
/// <param name="keyEventArgs">Arguments generated by key event</param>
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;
}
}
/// <summary>
/// Create new instance of <see cref="PartialKeyGesture"/> from <see cref="KeyGesture"/>
/// </summary>
/// <param name="gesture">Key gesture</param>
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;
}
}
/// <summary>
/// Create new instance of <see cref="PartialKeyGesture"/> having key and modifiers
/// </summary>
/// <param name="key">The key associated with partial key gesture</param>
/// <param name="modifiers">Modifier keys associated with partial key gesture</param>
public PartialKeyGesture(Key key, ModifierKeys modifiers)
: base(Key.None, ModifierKeys.None)
{
_key = key;
_modifiers = modifiers;
}
/// <summary>
/// Create new instance of<see cref="PartialKeyGesture"/> having only key and no modifiers
/// </summary>
/// <param name="key">The key associated with partial key gesture</param>
public PartialKeyGesture(Key key)
: base(Key.None, ModifierKeys.None)
{
_key = key;
_modifiers = ModifierKeys.None;
}
/// <summary>
/// Create new instance of<see cref="PartialKeyGesture"/> having only key and no modifiers
/// </summary>
/// <param name="modifiers">Modifier keys associated with partial key gesture</param>
public PartialKeyGesture(ModifierKeys modifiers)
: base(Key.None, ModifierKeys.None)
{
_key = Key.None;
_modifiers = modifiers;
}
/// <summary>
/// Determines whether input event supporting data strictly (all modifiers and keys) matches this instance of <see cref="PartialKeyGesture"/>
/// </summary>
/// <param name="targetElement">The target</param>
/// <param name="inputEventArgs">Input event arguments</param>
/// <returns><code>true</code> if event data matches partial gesture; otherwise <code>false</code></returns>
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;
}
/// <summary>
/// Determines whether input event arguments partly matches (part of modifiers or/and a key) this instance of <see cref="PartialKeyGesture"/>
/// </summary>
/// <param name="targetElement">The target</param>
/// <param name="inputEventArgs">Input event arguments</param>
/// <returns><code>true</code> if event data matches partial gesture; otherwise <code>false</code></returns>
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;
}
/// <summary>
/// Gets value indicating whether this InputGesture is completed
///
/// Incomplete gestures are ones which have only modifiers or only
/// keys assigned
/// </summary>
public bool IsFull
{
get {
if(Key == Key.None) {
return false;
}
// and function keys are valid without modifier
if (Key >= Key.F1 && Key <= Key.F24) {
return true;
}
// Modifiers alone are not valid
if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt,
Key.LeftShift, Key.RightShift,
Key.LeftCtrl, Key.RightCtrl,
Key.LWin, Key.RWin,
Key.System}, Key) > -1) {
return false;
}
// All other gestures must have modifier (except shift alone because it would mean uppercase)
if((Modifiers & (ModifierKeys.Windows | ModifierKeys.Control | ModifierKeys.Alt)) != ModifierKeys.None) {
return true;
}
return false;
}
}
/// <summary>
/// Creates string that represents <see cref="PartialKeyGesture"/>
/// </summary>
/// <returns>String representation of this object</returns>
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();
}
}
}

226
src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGestureConverter.cs

@ -6,127 +6,119 @@ using System.Windows.Input; @@ -6,127 +6,119 @@ using System.Windows.Input;
namespace ICSharpCode.Core.Presentation
{
/// <summary>
/// Converts <see cref="PartialKeyGesture"/> instance to and from other types
/// </summary>
public class PartialKeyGestureConverter : TypeConverter
{
private readonly KeyConverter keyConverter = new KeyConverter();
private readonly ModifierKeysConverter modidierKeysConverter = new ModifierKeysConverter();
/// <summary>
/// Determines whether object of specified type can be converted to instance of <see cref="PartialKeyGesture"/>
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked. </param>
/// <param name="sourceType">The type being evaluated for conversion. </param>
/// <returns>True if this converter can perform the operation; otherwise, false. </returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
/// <summary>
/// Converts <see cref="PartialKeyGesture"/> instance to and from other types
/// </summary>
public class PartialKeyGestureConverter : TypeConverter
{
private readonly KeyConverter keyConverter = new KeyConverter();
private readonly ModifierKeysConverter modidierKeysConverter = new ModifierKeysConverter();
/// <summary>
/// Determines whether object of specified type can be converted to instance of <see cref="PartialKeyGesture"/>
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked. </param>
/// <param name="sourceType">The type being evaluated for conversion. </param>
/// <returns>True if this converter can perform the operation; otherwise, false. </returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if(sourceType == typeof(string))
{
return true;
if(sourceType == typeof(string)) {
return true;
}
return base.CanConvertFrom(context, sourceType);
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// Determines whether an instance of <see cref="PartialKeyGesture"/> can be converted to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="destinationType">The type being evaluated for conversion. </param>
/// <returns>True if this converter can perform the operation; otherwise, false. </returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, destinationType);
}
/// <summary>
/// Attempts to convert a <see cref="PartialKeyGesture"/> to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information. </param>
/// <param name="value">The object to convert</param>
/// <param name="destinationType">The type wich instance of <see cref="PartialKeyGesture"/> is being converted to.</param>
/// <returns>The converted object, or an empty string if value is a null reference</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value == null && destinationType == typeof(string))
{
return String.Empty;
}
if(value is PartialKeyGesture && destinationType == typeof(string))
{
var partialKeyGesture = value as PartialKeyGesture;
var modifierString = (string)new ModifierKeysConverter().ConvertTo(context, culture, partialKeyGesture.Modifiers, typeof(string));
var keyString = (string)new KeyConverter().ConvertTo(context, culture, partialKeyGesture.Key, typeof(string));
var sb = new StringBuilder();
sb.Append(modifierString);
if(!string.IsNullOrEmpty(keyString) && !string.IsNullOrEmpty(modifierString))
{
sb.Append("+");
}
sb.Append(keyString);
return sb.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
/// <summary>
/// Attempts to convert the specified object to a <see cref="PartialKeyGesture"/>, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information.</param>
/// <param name="value">The object to convert</param>
/// <returns>The converted object.</returns>
/// <summary>
/// Determines whether an instance of <see cref="PartialKeyGesture"/> can be converted to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="destinationType">The type being evaluated for conversion. </param>
/// <returns>True if this converter can perform the operation; otherwise, false. </returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string)) {
return true;
}
return base.CanConvertFrom(context, destinationType);
}
/// <summary>
/// Attempts to convert a <see cref="PartialKeyGesture"/> to the specified type, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information. </param>
/// <param name="value">The object to convert</param>
/// <param name="destinationType">The type wich instance of <see cref="PartialKeyGesture"/> is being converted to.</param>
/// <returns>The converted object, or an empty string if value is a null reference</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value == null && destinationType == typeof(string)) {
return String.Empty;
}
if(value is PartialKeyGesture && destinationType == typeof(string)) {
var partialKeyGesture = value as PartialKeyGesture;
var modifierString = (string)new ModifierKeysConverter().ConvertTo(context, culture, partialKeyGesture.Modifiers, typeof(string));
var keyString = (string)new KeyConverter().ConvertTo(context, culture, partialKeyGesture.Key, typeof(string));
var sb = new StringBuilder();
sb.Append(modifierString);
if(!string.IsNullOrEmpty(keyString) && !string.IsNullOrEmpty(modifierString)) {
sb.Append("+");
}
sb.Append(keyString);
return sb.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
/// <summary>
/// Attempts to convert the specified object to a <see cref="PartialKeyGesture"/>, using the specified context.
/// </summary>
/// <param name="context">A format context that provides information about the environment from which this converter is being invoked.</param>
/// <param name="culture">Culture specific information.</param>
/// <param name="value">The object to convert</param>
/// <returns>The converted object.</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var gestureString = value as string;
if (gestureString != null)
{
var keysStart = gestureString.LastIndexOf('+');
if (keysStart > 0)
{
var modifierKeysString = gestureString.Substring(0, keysStart);
var keyString = gestureString.Substring(keysStart + 1);
var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, modifierKeysString);
var key = (Key)keyConverter.ConvertFrom(context, culture, keyString);
return new PartialKeyGesture(key, modifierKeys);
}
try
{
var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, gestureString);
return new PartialKeyGesture(modifierKeys);
}
catch (NotSupportedException)
{ }
try
{
var key = (Key)keyConverter.ConvertFrom(context, culture, gestureString);
return new PartialKeyGesture(key);
}
catch (NotSupportedException)
{ }
}
return base.ConvertFrom(context, culture, value);
var gestureString = value as string;
if (gestureString != null) {
var keysStart = gestureString.LastIndexOf('+');
if (keysStart > 0) {
var modifierKeysString = gestureString.Substring(0, keysStart);
var keyString = gestureString.Substring(keysStart + 1);
var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, modifierKeysString);
var key = (Key)keyConverter.ConvertFrom(context, culture, keyString);
return new PartialKeyGesture(key, modifierKeys);
}
try {
var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, gestureString);
return new PartialKeyGesture(modifierKeys);
}
catch (NotSupportedException)
{ }
try
{
var key = (Key)keyConverter.ConvertFrom(context, culture, gestureString);
return new PartialKeyGesture(key);
}
catch (NotSupportedException)
{ }
}
return base.ConvertFrom(context, culture, value);
}
}
}
}

Loading…
Cancel
Save