Browse Source

Track mouse leave events.

*Actually* fixes #15.
pull/16/head
Steven Kirk 12 years ago
parent
commit
686b339e5d
  1. 2
      Perspex.Input/IInputManager.cs
  2. 17
      Perspex.Input/InputManager.cs
  3. 74
      Perspex.Input/MouseDevice.cs
  4. 4
      Perspex.Input/Raw/RawMouseEventArgs.cs
  5. 11
      Windows/Perspex.Win32/Interop/UnmanagedMethods.cs
  6. 25
      Windows/Perspex.Win32/WindowImpl.cs

2
Perspex.Input/IInputManager.cs

@ -14,6 +14,8 @@ namespace Perspex.Input
{ {
IObservable<RawInputEventArgs> RawEventReceived { get; } IObservable<RawInputEventArgs> RawEventReceived { get; }
void ClearPointerOver(IPointerDevice device);
void Process(RawInputEventArgs e); void Process(RawInputEventArgs e);
void SetPointerOver(IPointerDevice device, IVisual visual, Point p); void SetPointerOver(IPointerDevice device, IVisual visual, Point p);

17
Perspex.Input/InputManager.cs

@ -23,6 +23,23 @@ namespace Perspex.Input
get { return this.rawEventReceived; } get { return this.rawEventReceived; }
} }
public void ClearPointerOver(IPointerDevice device)
{
foreach (var control in this.pointerOvers.ToList())
{
PointerEventArgs e = new PointerEventArgs
{
RoutedEvent = InputElement.PointerLeaveEvent,
Device = device,
OriginalSource = control,
Source = control,
};
this.pointerOvers.Remove(control);
control.RaiseEvent(e);
}
}
public void Process(RawInputEventArgs e) public void Process(RawInputEventArgs e)
{ {
this.rawEventReceived.OnNext(e); this.rawEventReceived.OnNext(e);

74
Perspex.Input/MouseDevice.cs

@ -76,8 +76,8 @@ namespace Perspex.Input
switch (e.Type) switch (e.Type)
{ {
case RawMouseEventType.Move: case RawMouseEventType.LeaveWindow:
this.MouseMove(mouse, e.Root, e.Position); this.LeaveWindow(mouse, e.Root);
break; break;
case RawMouseEventType.LeftButtonDown: case RawMouseEventType.LeftButtonDown:
this.MouseDown(mouse, e.Timestamp, e.Root, e.Position); this.MouseDown(mouse, e.Timestamp, e.Root, e.Position);
@ -85,44 +85,18 @@ namespace Perspex.Input
case RawMouseEventType.LeftButtonUp: case RawMouseEventType.LeftButtonUp:
this.MouseUp(mouse, e.Root, e.Position); this.MouseUp(mouse, e.Root, e.Position);
break; break;
case RawMouseEventType.Move:
this.MouseMove(mouse, e.Root, e.Position);
break;
case RawMouseEventType.Wheel: case RawMouseEventType.Wheel:
this.MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta); this.MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta);
break; break;
} }
} }
private void MouseMove(IMouseDevice device, IInputElement root, Point p) private void LeaveWindow(IMouseDevice device, IInputElement root)
{ {
IInteractive source; this.InputManager.ClearPointerOver(this);
if (this.Captured == null)
{
this.InputManager.SetPointerOver(this, root, p);
source = root as IInteractive;
}
else
{
Point offset = new Point();
foreach (IVisual ancestor in this.Captured.GetVisualAncestors())
{
offset += ancestor.Bounds.Position;
}
this.InputManager.SetPointerOver(this, this.Captured, p - offset);
source = this.Captured as IInteractive;
}
if (source != null)
{
source.RaiseEvent(new PointerEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerMovedEvent,
OriginalSource = source,
Source = source,
});
}
} }
private void MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p) private void MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p)
@ -167,6 +141,40 @@ namespace Perspex.Input
} }
} }
private void MouseMove(IMouseDevice device, IInputElement root, Point p)
{
IInteractive source;
if (this.Captured == null)
{
this.InputManager.SetPointerOver(this, root, p);
source = root as IInteractive;
}
else
{
Point offset = new Point();
foreach (IVisual ancestor in this.Captured.GetVisualAncestors())
{
offset += ancestor.Bounds.Position;
}
this.InputManager.SetPointerOver(this, this.Captured, p - offset);
source = this.Captured as IInteractive;
}
if (source != null)
{
source.RaiseEvent(new PointerEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerMovedEvent,
OriginalSource = source,
Source = source,
});
}
}
private void MouseUp(IMouseDevice device, IInputElement root, Point p) private void MouseUp(IMouseDevice device, IInputElement root, Point p)
{ {
var hit = this.HitTest(root, p); var hit = this.HitTest(root, p);

4
Perspex.Input/Raw/RawMouseEventArgs.cs

@ -7,13 +7,13 @@
namespace Perspex.Input.Raw namespace Perspex.Input.Raw
{ {
using System; using System;
using Perspex.Layout;
public enum RawMouseEventType public enum RawMouseEventType
{ {
Move, LeaveWindow,
LeftButtonDown, LeftButtonDown,
LeftButtonUp, LeftButtonUp,
Move,
Wheel, Wheel,
} }

11
Windows/Perspex.Win32/Interop/UnmanagedMethods.cs

@ -548,6 +548,9 @@ namespace Perspex.Win32.Interop
int bufferSize, int bufferSize,
uint flags); uint flags);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool TrackMouseEvent(ref TRACKMOUSEEVENT lpEventTrack);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool TranslateMessage(ref MSG lpMsg); public static extern bool TranslateMessage(ref MSG lpMsg);
@ -608,6 +611,14 @@ namespace Perspex.Win32.Interop
public int bottom; public int bottom;
} }
public struct TRACKMOUSEEVENT
{
public int cbSize;
public uint dwFlags;
public IntPtr hwndTrack;
public int dwHoverTime;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WNDCLASSEX public struct WNDCLASSEX
{ {

25
Windows/Perspex.Win32/WindowImpl.cs

@ -26,6 +26,8 @@ namespace Perspex.Win32
private Window owner; private Window owner;
private bool trackingMouse;
public WindowImpl() public WindowImpl()
{ {
this.CreateWindow(); this.CreateWindow();
@ -188,6 +190,19 @@ namespace Perspex.Win32
break; break;
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE: case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
if (!this.trackingMouse)
{
var tm = new UnmanagedMethods.TRACKMOUSEEVENT
{
cbSize = Marshal.SizeOf(typeof(UnmanagedMethods.TRACKMOUSEEVENT)),
dwFlags = 2,
hwndTrack = this.hwnd,
dwHoverTime = 0,
};
UnmanagedMethods.TrackMouseEvent(ref tm);
}
e = new RawMouseEventArgs( e = new RawMouseEventArgs(
WindowsMouseDevice.Instance, WindowsMouseDevice.Instance,
timestamp, timestamp,
@ -205,6 +220,16 @@ namespace Perspex.Win32
new Vector(0, ((int)wParam >> 16) / WheelDelta)); new Vector(0, ((int)wParam >> 16) / WheelDelta));
break; break;
case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE:
this.trackingMouse = false;
e = new RawMouseEventArgs(
WindowsMouseDevice.Instance,
timestamp,
this.owner,
RawMouseEventType.LeaveWindow,
new Point());
break;
case UnmanagedMethods.WindowsMessage.WM_PAINT: case UnmanagedMethods.WindowsMessage.WM_PAINT:
UnmanagedMethods.PAINTSTRUCT ps; UnmanagedMethods.PAINTSTRUCT ps;

Loading…
Cancel
Save