Browse Source

Implemented Tab focus.

Should hopefully be the start of a non-hacky tab focus solution.
pull/58/head
Steven Kirk 12 years ago
parent
commit
b369c30a2e
  1. 12
      Perspex.Application/Application.cs
  2. 6
      Perspex.Base/PerspexProperty.cs
  3. 14
      Perspex.Controls/ItemsControl.cs
  4. 2
      Perspex.Controls/Presenters/ItemsPresenter.cs
  5. 9
      Perspex.Controls/Primitives/SelectingItemsControl.cs
  6. 1
      Perspex.Controls/TabItem.cs
  7. 27
      Perspex.Input/FocusManager.cs
  8. 2
      Perspex.Input/IInputManager.cs
  9. 4
      Perspex.Input/IKeyboardDevice.cs
  10. 12
      Perspex.Input/IKeyboardNavigation.cs
  11. 18
      Perspex.Input/InputElement.cs
  12. 10
      Perspex.Input/InputManager.cs
  13. 28
      Perspex.Input/KeyboardDevice.cs
  14. 276
      Perspex.Input/KeyboardNavigation.cs
  15. 16
      Perspex.Input/KeyboardNavigationMode.cs
  16. 1
      Perspex.Input/Perspex.Input.csproj
  17. 7
      Perspex.sln
  18. 10
      Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
  19. 30
      Tests/Perspex.Controls.UnitTests/packages.config
  20. 856
      Tests/Perspex.Input.UnitTests/KeyboardNavigationTests.cs
  21. 134
      Tests/Perspex.Input.UnitTests/Perspex.Input.UnitTests.csproj
  22. 36
      Tests/Perspex.Input.UnitTests/Properties/AssemblyInfo.cs
  23. 11
      Tests/Perspex.Input.UnitTests/app.config
  24. 13
      Tests/Perspex.Input.UnitTests/packages.config
  25. 2
      Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs

12
Perspex.Application/Application.cs

@ -70,12 +70,6 @@ namespace Perspex
private set;
}
public KeyboardNavigation KeyboardNavigation
{
get;
private set;
}
public Styles Styles
{
get;
@ -91,17 +85,17 @@ namespace Perspex
protected virtual void RegisterServices()
{
var keyboardNavigation = new KeyboardNavigation();
this.FocusManager = new FocusManager();
this.InputManager = new InputManager();
this.KeyboardNavigation = new KeyboardNavigation();
Locator.CurrentMutable.Register(() => this, typeof(IGlobalDataTemplates));
Locator.CurrentMutable.Register(() => this, typeof(IGlobalStyles));
Locator.CurrentMutable.Register(() => this.FocusManager, typeof(IFocusManager));
Locator.CurrentMutable.Register(() => this.InputManager, typeof(IInputManager));
Locator.CurrentMutable.Register(() => this.KeyboardNavigation, typeof(IKeyboardNavigation));
Locator.CurrentMutable.Register(() => keyboardNavigation, typeof(IKeyboardNavigation));
Locator.CurrentMutable.Register(() => this.styler, typeof(IStyler));
Locator.CurrentMutable.Register(() => new LayoutManager(), typeof(ILayoutManager));
Locator.CurrentMutable.Register(() => new RenderManager(), typeof(IRenderManager));
}

6
Perspex.Base/PerspexProperty.cs

@ -39,11 +39,6 @@ namespace Perspex
/// </summary>
private Subject<PerspexPropertyChangedEventArgs> changed = new Subject<PerspexPropertyChangedEventArgs>();
/// <summary>
/// The coerce function.
/// </summary>
private Func<PerspexObject, object, object> coerce;
/// <summary>
/// Initializes a new instance of the <see cref="PerspexProperty"/> class.
/// </summary>
@ -183,7 +178,6 @@ namespace Perspex
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<PerspexObject, TValue, TValue> coerce = null)
where TOwner : PerspexObject
{
Contract.Requires<NullReferenceException>(name != null);

14
Perspex.Controls/ItemsControl.cs

@ -35,8 +35,6 @@ namespace Perspex.Controls
private PerspexReadOnlyListView<IVisual, ILogical> logicalChildren =
new PerspexReadOnlyListView<IVisual, ILogical>(x => (ILogical)x);
private ItemsPresenter presenter;
public ItemsControl()
{
this.GetObservableWithHistory(ItemsProperty).Subscribe(this.ItemsChanged);
@ -76,6 +74,12 @@ namespace Perspex.Controls
}
}
protected ItemsPresenter Presenter
{
get;
private set;
}
protected virtual ItemContainerGenerator CreateItemContainerGenerator()
{
return new ItemContainerGenerator(this);
@ -83,11 +87,11 @@ namespace Perspex.Controls
protected override void OnTemplateApplied()
{
this.presenter = this.FindTemplateChild<ItemsPresenter>("itemsPresenter");
this.Presenter = this.FindTemplateChild<ItemsPresenter>("itemsPresenter");
if (this.presenter != null)
if (this.Presenter != null)
{
this.logicalChildren.Source = ((IVisual)this.presenter.Panel).VisualChildren;
this.logicalChildren.Source = ((IVisual)this.Presenter.Panel).VisualChildren;
}
}

2
Perspex.Controls/Presenters/ItemsPresenter.cs

@ -11,6 +11,7 @@ namespace Perspex.Controls.Presenters
using System.Collections.Specialized;
using System.Reactive.Linq;
using Perspex.Controls.Generators;
using Perspex.Input;
using Perspex.Styling;
public class ItemsPresenter : Control, IVisual, IPresenter, ITemplatedControl
@ -71,6 +72,7 @@ namespace Perspex.Controls.Presenters
this.ClearVisualChildren();
this.Panel = this.ItemsPanel.Build();
this.Panel.TemplatedParent = this;
KeyboardNavigation.SetTabNavigation(this.Panel, KeyboardNavigationMode.Once);
((IItemsPanel)this.Panel).ChildLogicalParent = this.TemplatedParent as ILogical;
this.AddVisualChild(this.Panel);
this.createdPanel = true;

9
Perspex.Controls/Primitives/SelectingItemsControl.cs

@ -72,9 +72,11 @@ namespace Perspex.Controls.Primitives
switch (direction)
{
case FocusNavigationDirection.Up:
case FocusNavigationDirection.Left:
offset = -1;
break;
case FocusNavigationDirection.Down:
case FocusNavigationDirection.Right:
offset = 1;
break;
}
@ -94,6 +96,8 @@ namespace Perspex.Controls.Primitives
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
switch (e.Key)
{
case Key.Up:
@ -143,6 +147,11 @@ namespace Perspex.Controls.Primitives
this.ItemContainerGenerator.GetContainerForItem(selected) :
null;
if (this.Presenter != null && this.Presenter.Panel != null)
{
KeyboardNavigation.SetTabOnceActiveElement(this.Presenter.Panel, selectedContainer);
}
foreach (var item in containers)
{
item.IsSelected = item == selectedContainer;

1
Perspex.Controls/TabItem.cs

@ -15,6 +15,7 @@ namespace Perspex.Controls
static TabItem()
{
FocusableProperty.OverrideDefaultValue(typeof(TabItem), true);
Control.AffectsRender(IsSelectedProperty);
Control.PseudoClass(IsSelectedProperty, ":selected");
}

27
Perspex.Input/FocusManager.cs

@ -25,8 +25,7 @@ namespace Perspex.Input
public IInputElement Current
{
get;
private set;
get { return KeyboardDevice.Instance.FocusedElement; }
}
public IFocusScope Scope
@ -84,29 +83,7 @@ namespace Perspex.Input
if (this.Scope == scope)
{
var interactive = this.Current as IInteractive;
if (interactive != null)
{
interactive.RaiseEvent(new RoutedEventArgs
{
RoutedEvent = InputElement.LostFocusEvent,
});
}
this.Current = element;
KeyboardDevice.Instance.FocusedElement = element;
interactive = element as IInteractive;
if (interactive != null)
{
interactive.RaiseEvent(new GotFocusEventArgs
{
RoutedEvent = InputElement.GotFocusEvent,
KeyboardNavigated = keyboardNavigated,
});
}
KeyboardDevice.Instance.SetFocusedElement(element, keyboardNavigated);
}
}

2
Perspex.Input/IInputManager.cs

@ -14,6 +14,8 @@ namespace Perspex.Input
{
IObservable<RawInputEventArgs> RawEventReceived { get; }
IObservable<RawInputEventArgs> PostProcess { get; }
void Process(RawInputEventArgs e);
}
}

4
Perspex.Input/IKeyboardDevice.cs

@ -28,8 +28,10 @@ namespace Perspex.Input
public interface IKeyboardDevice : IInputDevice
{
IInputElement FocusedElement { get; set; }
IInputElement FocusedElement { get; }
ModifierKeys Modifiers { get; }
void SetFocusedElement(IInputElement element, bool keyboardNavigated);
}
}

12
Perspex.Input/IKeyboardNavigation.cs

@ -1,5 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="IKeyboardDevice.cs" company="Steven Kirk">
// <copyright file="KeyboardNavigation.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
@ -8,8 +8,14 @@ namespace Perspex.Input
{
public interface IKeyboardNavigation
{
bool MoveNext(IInputElement element);
IInputElement GetNextInTabOrder(IInputElement element);
bool MovePrevious(IInputElement element);
IInputElement GetPreviousInTabOrder(IInputElement element);
void TabNext(IInputElement element);
void TabPrevious(IInputElement element);
void TabTo(IInputElement element);
}
}

18
Perspex.Input/InputElement.cs

@ -226,24 +226,20 @@ namespace Perspex.Input
protected virtual void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Tab)
if (e.Key == Key.Tab && !e.Handled)
{
var modifiers = e.Device.Modifiers;
var shift = (e.Device.Modifiers & ModifierKeys.Shift) != 0;
if ((modifiers & ModifierKeys.Shift) == 0)
if (!shift)
{
if (KeyboardNavigation.Instance.MoveNext(this))
{
e.Handled = true;
}
KeyboardNavigation.Instance.TabNext(this);
}
else
{
if (KeyboardNavigation.Instance.MovePrevious(this))
{
e.Handled = true;
}
KeyboardNavigation.Instance.TabPrevious(this);
}
e.Handled = true;
}
}

10
Perspex.Input/InputManager.cs

@ -17,10 +17,18 @@ namespace Perspex.Input
{
private Subject<RawInputEventArgs> rawEventReceived = new Subject<RawInputEventArgs>();
private Subject<RawInputEventArgs> postProcess = new Subject<RawInputEventArgs>();
public static IInputManager Instance => Locator.Current.GetService<IInputManager>();
public IObservable<RawInputEventArgs> RawEventReceived => this.rawEventReceived;
public void Process(RawInputEventArgs e) => this.rawEventReceived.OnNext(e);
public IObservable<RawInputEventArgs> PostProcess => this.postProcess;
public void Process(RawInputEventArgs e)
{
this.rawEventReceived.OnNext(e);
this.postProcess.OnNext(e);
}
}
}

28
Perspex.Input/KeyboardDevice.cs

@ -10,6 +10,7 @@ namespace Perspex.Input
using System.Linq;
using System.Reactive.Linq;
using Perspex.Input.Raw;
using Perspex.Interactivity;
using Splat;
public abstract class KeyboardDevice : IKeyboardDevice
@ -40,11 +41,36 @@ namespace Perspex.Input
public IInputElement FocusedElement
{
get;
set;
private set;
}
public abstract ModifierKeys Modifiers { get; }
public void SetFocusedElement(IInputElement element, bool keyboardNavigated)
{
var interactive = this.FocusedElement as IInteractive;
if (interactive != null)
{
interactive.RaiseEvent(new RoutedEventArgs
{
RoutedEvent = InputElement.LostFocusEvent,
});
}
this.FocusedElement = element;
interactive = element as IInteractive;
if (interactive != null)
{
interactive.RaiseEvent(new GotFocusEventArgs
{
RoutedEvent = InputElement.GotFocusEvent,
KeyboardNavigated = keyboardNavigated,
});
}
}
private void ProcessRawEvent(RawKeyEventArgs e)
{
IInputElement element = this.FocusedElement;

276
Perspex.Input/KeyboardNavigation.cs

@ -6,81 +6,289 @@
namespace Perspex.Input
{
using System;
using System.Collections.Generic;
using System.Linq;
using Perspex.VisualTree;
using Splat;
public class KeyboardNavigation : IKeyboardNavigation
{
public static readonly PerspexProperty<KeyboardNavigationMode> TabNavigationProperty =
PerspexProperty.RegisterAttached<KeyboardNavigation, InputElement, KeyboardNavigationMode>("TabNavigation");
public static readonly PerspexProperty<IInputElement> TabOnceActiveElementProperty =
PerspexProperty.RegisterAttached<KeyboardNavigation, InputElement, IInputElement>("TabOnceActiveElement");
public static IKeyboardNavigation Instance
{
get { return Locator.Current.GetService<IKeyboardNavigation>(); }
}
public bool MoveNext(IInputElement element)
public static KeyboardNavigationMode GetTabNavigation(InputElement element)
{
var parent = element.GetVisualParent();
var descendent = element.GetVisualDescendents()
.OfType<IInputElement>()
.Where(x => x.Focusable && x.IsEnabledCore)
.FirstOrDefault();
return element.GetValue(TabNavigationProperty);
}
public static void SetTabNavigation(InputElement element, KeyboardNavigationMode value)
{
element.SetValue(TabNavigationProperty, value);
}
public static IInputElement GetTabOnceActiveElement(InputElement element)
{
return element.GetValue(TabOnceActiveElementProperty);
}
public static void SetTabOnceActiveElement(InputElement element, IInputElement value)
{
element.SetValue(TabOnceActiveElementProperty, value);
}
public IInputElement GetNextInTabOrder(IInputElement element)
{
Contract.Requires<ArgumentNullException>(element != null);
var container = element.GetVisualParent<IInputElement>();
if (container != null)
{
var mode = GetTabNavigation((InputElement)container);
switch (mode)
{
case KeyboardNavigationMode.Continue:
return GetNextInContainer(element, container) ??
GetFirstInNextContainer(container);
case KeyboardNavigationMode.Cycle:
return GetNextInContainer(element, container) ??
GetDescendents(container).FirstOrDefault();
default:
return GetFirstInNextContainer(container);
}
}
else
{
return GetDescendents(element).FirstOrDefault();
}
}
public IInputElement GetPreviousInTabOrder(IInputElement element)
{
Contract.Requires<ArgumentNullException>(element != null);
var container = element.GetVisualParent<IInputElement>();
if (container != null)
{
var mode = GetTabNavigation((InputElement)container);
switch (mode)
{
case KeyboardNavigationMode.Continue:
return GetPreviousInContainer(element, container) ??
GetLastInPreviousContainer(element);
case KeyboardNavigationMode.Cycle:
return GetPreviousInContainer(element, container) ??
GetDescendents(container).LastOrDefault();
default:
return GetLastInPreviousContainer(container);
}
}
else
{
return GetDescendents(element).LastOrDefault();
}
}
public void TabNext(IInputElement element)
{
Contract.Requires<ArgumentNullException>(element != null);
var next = GetNextInTabOrder(element);
if (next != null)
{
TabTo(next);
}
}
public void TabPrevious(IInputElement element)
{
Contract.Requires<ArgumentNullException>(element != null);
var next = GetPreviousInTabOrder(element);
if (next != null)
{
TabTo(next);
}
}
public void TabTo(IInputElement element)
{
Contract.Requires<ArgumentNullException>(element != null);
FocusManager.Instance.Focus(element, true);
}
private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEnabledCore && e.IsVisible;
private static bool CanFocusDescendent(IInputElement e) => e.IsEnabledCore && e.IsVisible;
private static IEnumerable<IInputElement> GetDescendents(IInputElement element)
{
var mode = GetTabNavigation((InputElement)element);
if (mode == KeyboardNavigationMode.Never)
{
yield break;
}
var children = element.GetVisualChildren().OfType<IInputElement>();
if (mode == KeyboardNavigationMode.Once)
{
var active = GetTabOnceActiveElement((InputElement)element);
if (active != null)
{
yield return active;
yield break;
}
else
{
children = children.Take(1);
}
}
foreach (var child in children)
{
if (CanFocus(child))
{
yield return child;
}
if (CanFocusDescendent(child))
{
foreach (var descendent in GetDescendents(child))
{
yield return descendent;
}
}
}
}
private static IInputElement GetNextInContainer(IInputElement element, IInputElement container)
{
var descendent = GetDescendents(element).FirstOrDefault();
if (descendent != null)
{
FocusManager.Instance.Focus(descendent, true);
return true;
return descendent;
}
else if (parent != null)
else if (container != null)
{
var sibling = parent.GetVisualChildren()
var sibling = container.GetVisualChildren()
.OfType<IInputElement>()
.Where(x => x.Focusable && x.IsEnabledCore)
.Where(CanFocus)
.SkipWhile(x => x != element)
.Skip(1)
.FirstOrDefault();
if (sibling != null)
{
FocusManager.Instance.Focus(sibling, true);
return true;
return sibling;
}
}
return false;
return null;
}
public bool MovePrevious(IInputElement element)
private static IInputElement GetPreviousInContainer(IInputElement element, IInputElement container)
{
var parent = element.GetVisualParent();
var descendent = element.GetVisualDescendents()
return container.GetVisualChildren()
.OfType<IInputElement>()
.Where(x => x.Focusable && x.IsEnabledCore)
.Reverse()
.FirstOrDefault();
.Where(CanFocus)
.TakeWhile(x => x != element)
.LastOrDefault();
}
if (descendent != null)
{
FocusManager.Instance.Focus(descendent, true);
return true;
}
else if (parent != null)
private static IInputElement GetFirstInNextContainer(IInputElement container)
{
var parent = container.GetVisualParent<IInputElement>();
IInputElement next = null;
if (parent != null)
{
var previous = parent.GetVisualChildren()
var sibling = parent.GetVisualChildren()
.OfType<IInputElement>()
.Where(x => x.Focusable && x.IsEnabledCore)
.Reverse()
.SkipWhile(x => x != element)
.Where(CanFocusDescendent)
.SkipWhile(x => x != container)
.Skip(1)
.FirstOrDefault();
if (previous != null)
if (sibling != null)
{
if (CanFocus(sibling))
{
next = sibling;
}
else
{
next = GetDescendents(sibling).FirstOrDefault();
}
}
if (next == null)
{
next = GetFirstInNextContainer(parent);
}
}
else
{
next = GetDescendents(container).FirstOrDefault();
}
return next;
}
private static IInputElement GetLastInPreviousContainer(IInputElement container)
{
var parent = container.GetVisualParent<IInputElement>();
IInputElement next = null;
if (parent != null)
{
var sibling = parent.GetVisualChildren()
.OfType<IInputElement>()
.Where(CanFocusDescendent)
.TakeWhile(x => x != container)
.LastOrDefault();
if (sibling != null)
{
FocusManager.Instance.Focus(previous, true);
return true;
if (CanFocus(sibling))
{
next = sibling;
}
else
{
next = GetDescendents(sibling).LastOrDefault();
}
}
if (next == null)
{
next = GetLastInPreviousContainer(parent);
}
}
else
{
next = GetDescendents(container).LastOrDefault();
}
return false;
return next;
}
}
}

16
Perspex.Input/KeyboardNavigationMode.cs

@ -0,0 +1,16 @@
// -----------------------------------------------------------------------
// <copyright file="KeyboardNavigationMode.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Input
{
public enum KeyboardNavigationMode
{
Continue,
Cycle,
Once,
Never,
}
}

1
Perspex.Input/Perspex.Input.csproj

@ -81,6 +81,7 @@
<Compile Include="PointerWheelEventArgs.cs" />
<Compile Include="Raw\RawMouseWheelEventArgs.cs" />
<Compile Include="Raw\RawSizeEventArgs.cs" />
<Compile Include="KeyboardNavigationMode.cs" />
<Compile Include="VectorEventArgs.cs" />
<Compile Include="KeyEventArgs.cs" />
<Compile Include="MouseDevice.cs" />

7
Perspex.sln

@ -65,6 +65,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1.RenderTes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Cairo.RenderTests", "Tests\Perspex.RenderTests\Perspex.Cairo.RenderTests.csproj", "{E106CF37-4066-4615-B684-172A6D30B058}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input.UnitTests", "Tests\Perspex.Input.UnitTests\Perspex.Input.UnitTests.csproj", "{AC18926A-E784-40FE-B09D-BB0FE2B599F0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -175,6 +177,10 @@ Global
{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.Build.0 = Release|Any CPU
{AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -193,5 +199,6 @@ Global
{08478EF5-44E8-42E9-92D6-15E00EC038D8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{E106CF37-4066-4615-B684-172A6D30B058} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection
EndGlobal

10
Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

@ -41,11 +41,13 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll</HintPath>
</Reference>
<Reference Include="Ploeh.AutoFixture">
<HintPath>..\..\packages\AutoFixture.3.21.1\lib\net40\Ploeh.AutoFixture.dll</HintPath>
<Reference Include="Ploeh.AutoFixture, Version=3.30.3.0, Culture=neutral, PublicKeyToken=b24654c590009d4f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AutoFixture.3.30.3\lib\net40\Ploeh.AutoFixture.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ploeh.AutoFixture.AutoMoq">
<HintPath>..\..\packages\AutoFixture.AutoMoq.3.21.1\lib\net40\Ploeh.AutoFixture.AutoMoq.dll</HintPath>
<Reference Include="Ploeh.AutoFixture.AutoMoq, Version=3.30.3.0, Culture=neutral, PublicKeyToken=b24654c590009d4f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AutoFixture.AutoMoq.3.30.3\lib\net40\Ploeh.AutoFixture.AutoMoq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=1.6.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>

30
Tests/Perspex.Controls.UnitTests/packages.config

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoFixture" version="3.21.1" targetFramework="net45" />
<package id="AutoFixture.AutoMoq" version="3.21.1" targetFramework="net45" />
<package id="Moq" version="4.2.1409.1722" targetFramework="net45" />
<package id="Rx-Core" version="2.2.5" targetFramework="net45" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />
<package id="Rx-Linq" version="2.2.5" targetFramework="net45" />
<package id="Rx-Main" version="2.2.5" targetFramework="net45" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />
<package id="Splat" version="1.6.1" targetFramework="net45" />
<package id="xunit" version="2.0.0" targetFramework="net45" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
<package id="xunit.assert" version="2.0.0" targetFramework="net45" />
<package id="xunit.core" version="2.0.0" targetFramework="net45" />
<package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" />
<package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" />
<package id="AutoFixture" version="3.30.3" targetFramework="net45" userInstalled="true" />
<package id="AutoFixture.AutoMoq" version="3.30.3" targetFramework="net45" userInstalled="true" />
<package id="Moq" version="4.2.1409.1722" targetFramework="net45" userInstalled="true" />
<package id="Rx-Core" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Rx-Linq" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Rx-Main" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Splat" version="1.6.1" targetFramework="net45" userInstalled="true" />
<package id="xunit" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.assert" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.core" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" userInstalled="true" />
</packages>

856
Tests/Perspex.Input.UnitTests/KeyboardNavigationTests.cs

@ -0,0 +1,856 @@
// -----------------------------------------------------------------------
// <copyright file="KeyboardNavigationTests.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Input.UnitTests
{
using Perspex.Controls;
using Xunit;
public class KeyboardNavigationTests
{
[Fact]
public void GetNextInTabOrder_Continue_Returns_Next_Control_In_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
(current = new Button { Id = "Button2" }),
(next = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Continue_Returns_First_Control_In_Next_Sibling_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(current = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Continue_Returns_Next_Sibling()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(current = new Button { Id = "Button3" }),
}
}),
(next = new Button { Id = "Button4" }),
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Continue_Returns_First_Control_In_Next_Uncle_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(current = new Button { Id = "Button3" }),
}
}),
},
},
new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Continue_Returns_Child_Of_Top_Level()
{
Button next;
var top = new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button1" }),
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(top);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Continue_Wraps()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button1" }),
new Button { Id = "Button2" },
new Button { Id = "Button3" },
}
}),
},
},
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
(current = new Button { Id = "Button6" }),
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Cycle_Returns_Next_Control_In_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle,
Children = new Controls
{
new Button { Id = "Button1" },
(current = new Button { Id = "Button2" }),
(next = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Cycle_Wraps_To_First()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle,
Children = new Controls
{
(next = new Button { Id = "Button1" }),
new Button { Id = "Button2" },
(current = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Once_Moves_To_Next_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Once,
Children = new Controls
{
new Button { Id = "Button1" },
(current = new Button { Id = "Button2" }),
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Once_Moves_To_Active_Element()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Once,
Children = new Controls
{
new Button { Id = "Button1" },
(next = new Button { Id = "Button2" }),
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
(current = new Button { Id = "Button6" }),
}
},
}
};
KeyboardNavigation.SetTabOnceActiveElement(container, next);
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Never_Moves_To_Next_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Never,
Children = new Controls
{
new Button { Id = "Button1" },
(current = new Button { Id = "Button2" }),
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetNextInTabOrder_Never_Skips_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Never,
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
(next = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
(current = new Button { Id = "Button6" }),
}
},
}
};
KeyboardNavigation.SetTabOnceActiveElement(container, next);
var target = new KeyboardNavigation();
var result = target.GetNextInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Continue_Returns_Previous_Control_In_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
(next = new Button { Id = "Button2" }),
(current = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Continue_Returns_Last_Control_In_Previous_Sibling_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(next = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
(current = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Continue_Returns_Last_Child_Of_Sibling()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(next = new Button { Id = "Button3" }),
}
}),
(current = new Button { Id = "Button4" }),
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Continue_Returns_Last_Control_In_Previous_Nephew_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(next = new Button { Id = "Button3" }),
}
}),
},
},
new StackPanel
{
Children = new Controls
{
(current = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Continue_Wraps()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
(current = new Button { Id = "Button1" }),
new Button { Id = "Button2" },
new Button { Id = "Button3" },
}
}),
},
},
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
(next = new Button { Id = "Button6" }),
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Cycle_Returns_Previous_Control_In_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle,
Children = new Controls
{
(next = new Button { Id = "Button1" }),
(current = new Button { Id = "Button2" }),
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Cycle_Wraps_To_Last()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle,
Children = new Controls
{
(current = new Button { Id = "Button1" }),
new Button { Id = "Button2" },
(next = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
Children = new Controls
{
new Button { Id = "Button4" },
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Once_Moves_To_Previous_Container()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
Children = new Controls
{
new Button { Id = "Button1" },
new Button { Id = "Button2" },
(next = new Button { Id = "Button3" }),
}
}),
new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Once,
Children = new Controls
{
new Button { Id = "Button4" },
(current = new Button { Id = "Button5" }),
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Once_Moves_To_Active_Element()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Once,
Children = new Controls
{
new Button { Id = "Button1" },
(next = new Button { Id = "Button2" }),
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
(current = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
KeyboardNavigation.SetTabOnceActiveElement(container, next);
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
[Fact]
public void GetPreviousInTabOrder_Once_Moves_To_First_Element()
{
StackPanel container;
Button current;
Button next;
var top = new StackPanel
{
Children = new Controls
{
(container = new StackPanel
{
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Once,
Children = new Controls
{
(next = new Button { Id = "Button1" }),
new Button { Id = "Button2" },
new Button { Id = "Button3" },
}
}),
new StackPanel
{
Children = new Controls
{
(current = new Button { Id = "Button4" }),
new Button { Id = "Button5" },
new Button { Id = "Button6" },
}
},
}
};
var target = new KeyboardNavigation();
var result = target.GetPreviousInTabOrder(current);
Assert.Equal(next, result);
}
}
}

134
Tests/Perspex.Input.UnitTests/Perspex.Input.UnitTests.csproj

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" />
<Import Project="..\..\packages\xunit.core.2.0.0\build\Xamarin.iOS\xunit.core.props" Condition="Exists('..\..\packages\xunit.core.2.0.0\build\Xamarin.iOS\xunit.core.props')" />
<Import Project="..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props" Condition="Exists('..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AC18926A-E784-40FE-B09D-BB0FE2B599F0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.Input.UnitTests</RootNamespace>
<AssemblyName>Perspex.Input.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>90580c1a</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Moq, Version=4.2.1502.911, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\..\packages\Moq.4.2.1502.911\lib\net40\Moq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ploeh.AutoFixture, Version=3.30.3.0, Culture=neutral, PublicKeyToken=b24654c590009d4f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AutoFixture.3.30.3\lib\net40\Ploeh.AutoFixture.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ploeh.AutoFixture.AutoMoq, Version=3.30.3.0, Culture=neutral, PublicKeyToken=b24654c590009d4f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AutoFixture.AutoMoq.3.30.3\lib\net40\Ploeh.AutoFixture.AutoMoq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.assert, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.core, Version=2.0.0.2929, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="KeyboardNavigationTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Interactivity\Perspex.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Perspex.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Layout\Perspex.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.core.2.0.0\build\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.props'))" />
<Error Condition="!Exists('..\..\packages\xunit.core.2.0.0\build\Xamarin.iOS\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.core.2.0.0\build\Xamarin.iOS\xunit.core.props'))" />
<Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.0.0\build\net20\xunit.runner.visualstudio.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

36
Tests/Perspex.Input.UnitTests/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.Input.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Input.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ac18926a-e784-40fe-b09d-bb0fe2b599f0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

11
Tests/Perspex.Input.UnitTests/app.config

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Moq" publicKeyToken="69f491c39445e920" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1502.911" newVersion="4.2.1502.911" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

13
Tests/Perspex.Input.UnitTests/packages.config

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoFixture" version="3.30.3" targetFramework="net45" userInstalled="true" />
<package id="AutoFixture.AutoMoq" version="3.30.3" targetFramework="net45" userInstalled="true" />
<package id="Moq" version="4.2.1502.911" targetFramework="net45" userInstalled="true" />
<package id="Splat" version="1.6.2" targetFramework="net45" userInstalled="true" />
<package id="xunit" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.assert" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.core" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.extensibility.core" version="2.0.0" targetFramework="net45" userInstalled="true" />
<package id="xunit.runner.visualstudio" version="2.0.0" targetFramework="net45" userInstalled="true" />
</packages>

2
Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs

@ -54,7 +54,7 @@ namespace Perspex.Win32.Input
public void WindowActivated(Window window)
{
this.FocusedElement = window;
this.SetFocusedElement(window, false);
}
public string StringFromVirtualKey(uint virtualKey)

Loading…
Cancel
Save