diff --git a/Perspex.Windows/Input/MouseDevice.cs b/Perspex.Windows/Input/MouseDevice.cs new file mode 100644 index 0000000000..08d0253570 --- /dev/null +++ b/Perspex.Windows/Input/MouseDevice.cs @@ -0,0 +1,14 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Windows.Input +{ + using Perspex.Input; + + public class MouseDevice : IInputDevice + { + } +} diff --git a/Perspex.Windows/Perspex.Windows.csproj b/Perspex.Windows/Perspex.Windows.csproj index e8950efe2c..ba75d8f5d9 100644 --- a/Perspex.Windows/Perspex.Windows.csproj +++ b/Perspex.Windows/Perspex.Windows.csproj @@ -66,6 +66,7 @@ + diff --git a/Perspex.Windows/Window.cs b/Perspex.Windows/Window.cs index dac820691a..6ddbd227d0 100644 --- a/Perspex.Windows/Window.cs +++ b/Perspex.Windows/Window.cs @@ -13,21 +13,28 @@ namespace Perspex.Windows using System.Runtime.InteropServices; using Perspex.Controls; using Perspex.Input; + using Perspex.Input.Raw; using Perspex.Layout; + using Perspex.Windows.Input; using Perspex.Windows.Interop; using Perspex.Windows.Threading; + using Splat; public class Window : ContentControl, ILayoutRoot { public static readonly PerspexProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner(); + private static readonly IInputDevice MouseDevice = new MouseDevice(); + private UnmanagedMethods.WndProc wndProcDelegate; private string className; private Renderer renderer; + private IInputManager inputManager; + static Window() { FontSizeProperty.OverrideDefaultValue(typeof(Window), 18.0); @@ -39,6 +46,7 @@ namespace Perspex.Windows Size clientSize = this.ClientSize; this.LayoutManager = new LayoutManager(); this.renderer = new Renderer(this.Handle, (int)clientSize.Width, (int)clientSize.Height); + this.inputManager = Locator.Current.GetService(); this.Template = ControlTemplate.Create(this.DefaultTemplate); this.LayoutManager.LayoutNeeded.Subscribe(x => @@ -138,64 +146,11 @@ namespace Perspex.Windows } } - private void MouseDown(Visual visual, Point p) - { - IVisual hit = visual.GetVisualAt(p); - - if (hit != null) - { - Interactive source = (hit as Interactive) ?? hit.GetVisualAncestor(); - - if (source != null) - { - source.RaiseEvent(new PointerEventArgs - { - RoutedEvent = Control.PointerPressedEvent, - OriginalSource = source, - Source = source, - }); - } - } - } - - private void MouseMove(Visual visual, Point p) - { - Control control = visual as Control; - - if (control != null) - { - control.IsPointerOver = visual.Bounds.Contains(p); - } - - foreach (Visual child in ((IVisual)visual).VisualChildren) - { - this.MouseMove(child, p - visual.Bounds.Position); - } - } - - private void MouseUp(Visual visual, Point p) - { - IVisual hit = visual.GetVisualAt(p); - - if (hit != null) - { - Interactive source = (hit as Interactive) ?? hit.GetVisualAncestor(); - - if (source != null) - { - source.RaiseEvent(new PointerEventArgs - { - RoutedEvent = Control.PointerReleasedEvent, - OriginalSource = source, - Source = source, - }); - } - } - } - [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { + RawInputEventArgs e = null; + switch ((UnmanagedMethods.WindowsMessage)msg) { ////case UnmanagedMethods.WindowsMessage.WM_DESTROY: @@ -211,15 +166,27 @@ namespace Perspex.Windows //// break; case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN: - this.MouseDown(this, new Point((uint)lParam & 0xffff, (uint)lParam >> 16)); + e = new RawMouseEventArgs( + MouseDevice, + this, + RawMouseEventType.LeftButtonDown, + new Point((uint)lParam & 0xffff, (uint)lParam >> 16)); break; case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP: - this.MouseUp(this, new Point((uint)lParam & 0xffff, (uint)lParam >> 16)); + e = new RawMouseEventArgs( + MouseDevice, + this, + RawMouseEventType.LeftButtonUp, + new Point((uint)lParam & 0xffff, (uint)lParam >> 16)); break; case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE: - this.MouseMove(this, new Point((uint)lParam & 0xffff, (uint)lParam >> 16)); + e = new RawMouseEventArgs( + MouseDevice, + this, + RawMouseEventType.Move, + new Point((uint)lParam & 0xffff, (uint)lParam >> 16)); break; case UnmanagedMethods.WindowsMessage.WM_SIZE: @@ -228,6 +195,11 @@ namespace Perspex.Windows return IntPtr.Zero; } + if (e != null) + { + this.inputManager.Process(e); + } + return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); } } diff --git a/Perspex/Input/IInputDevice.cs b/Perspex/Input/IInputDevice.cs new file mode 100644 index 0000000000..f69f13e837 --- /dev/null +++ b/Perspex/Input/IInputDevice.cs @@ -0,0 +1,18 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + public interface IInputDevice + { + } +} diff --git a/Perspex/Input/IInputManager.cs b/Perspex/Input/IInputManager.cs new file mode 100644 index 0000000000..9c5fee1095 --- /dev/null +++ b/Perspex/Input/IInputManager.cs @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input +{ + using Perspex.Input.Raw; + + public interface IInputManager + { + void Process(RawInputEventArgs e); + } +} diff --git a/Perspex/Input/InputManager.cs b/Perspex/Input/InputManager.cs new file mode 100644 index 0000000000..d2341bd3f2 --- /dev/null +++ b/Perspex/Input/InputManager.cs @@ -0,0 +1,95 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input +{ + using Perspex.Controls; + using Perspex.Input.Raw; + + public class InputManager : IInputManager + { + public void Process(RawInputEventArgs e) + { + RawMouseEventArgs mouse = e as RawMouseEventArgs; + + if (mouse != null) + { + this.ProcessMouse(mouse); + } + } + + private void ProcessMouse(RawMouseEventArgs e) + { + switch (e.Type) + { + case RawMouseEventType.Move: + this.MouseMove((IVisual)e.Root, e.Position); + break; + case RawMouseEventType.LeftButtonDown: + this.MouseDown((IVisual)e.Root, e.Position); + break; + case RawMouseEventType.LeftButtonUp: + this.MouseUp((IVisual)e.Root, e.Position); + break; + } + } + + private void MouseMove(IVisual visual, Point p) + { + Control control = visual as Control; + + if (control != null) + { + control.IsPointerOver = visual.Bounds.Contains(p); + } + + foreach (IVisual child in visual.VisualChildren) + { + this.MouseMove(child, p - visual.Bounds.Position); + } + } + + private void MouseDown(IVisual visual, Point p) + { + IVisual hit = visual.GetVisualAt(p); + + if (hit != null) + { + Interactive source = (hit as Interactive) ?? hit.GetVisualAncestor(); + + if (source != null) + { + source.RaiseEvent(new PointerEventArgs + { + RoutedEvent = Control.PointerPressedEvent, + OriginalSource = source, + Source = source, + }); + } + } + } + + private void MouseUp(IVisual visual, Point p) + { + IVisual hit = visual.GetVisualAt(p); + + if (hit != null) + { + Interactive source = (hit as Interactive) ?? hit.GetVisualAncestor(); + + if (source != null) + { + source.RaiseEvent(new PointerEventArgs + { + RoutedEvent = Control.PointerReleasedEvent, + OriginalSource = source, + Source = source, + }); + } + } + } + } +} diff --git a/Perspex/Input/Raw/RawInputEventArgs.cs b/Perspex/Input/Raw/RawInputEventArgs.cs new file mode 100644 index 0000000000..0e9a08c6fe --- /dev/null +++ b/Perspex/Input/Raw/RawInputEventArgs.cs @@ -0,0 +1,27 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input.Raw +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using Perspex.Layout; + + public class RawInputEventArgs : EventArgs + { + public RawInputEventArgs(IInputDevice device) + { + Contract.Requires(device != null); + + this.Device = device; + } + + public IInputDevice Device { get; private set; } + } +} diff --git a/Perspex/Input/Raw/RawMouseEventArgs.cs b/Perspex/Input/Raw/RawMouseEventArgs.cs new file mode 100644 index 0000000000..41da9ec88a --- /dev/null +++ b/Perspex/Input/Raw/RawMouseEventArgs.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input.Raw +{ + using System; + using Perspex.Layout; + + public enum RawMouseEventType + { + Move, + LeftButtonDown, + LeftButtonUp, + } + + public class RawMouseEventArgs : RawInputEventArgs + { + public RawMouseEventArgs( + IInputDevice device, + ILayoutRoot root, + RawMouseEventType type, + Point position) + : base(device) + { + Contract.Requires(device != null); + Contract.Requires(root != null); + + this.Root = root; + this.Position = position; + this.Type = type; + } + + public ILayoutRoot Root { get; private set; } + + public Point Position { get; private set; } + + public RawMouseEventType Type { get; private set; } + } +} diff --git a/Perspex/Perspex.csproj b/Perspex/Perspex.csproj index 75228446c7..a85e1de6c6 100644 --- a/Perspex/Perspex.csproj +++ b/Perspex/Perspex.csproj @@ -73,6 +73,11 @@ + + + + + diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index 6655d8d818..1b45b30206 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using Perspex; using Perspex.Controls; +using Perspex.Input; using Perspex.Media; using Perspex.Styling; using Perspex.Themes.Default; @@ -37,7 +38,9 @@ namespace TestApplication static void Main(string[] args) { TextService textService = new TextService(new SharpDX.DirectWrite.Factory()); + InputManager inputManager = new InputManager(); + Locator.CurrentMutable.Register(() => inputManager, typeof(IInputManager)); Locator.CurrentMutable.Register(() => textService, typeof(ITextService)); Locator.CurrentMutable.Register(() => new Styler(), typeof(IStyler)); Locator.CurrentMutable.Register(() => new TestLogger(), typeof(ILogger));