Skip to content

Commit

Permalink
add MouseMoveTimerTriggered to fix lagging touch drags
Browse files Browse the repository at this point in the history
  • Loading branch information
dmg-hamann committed Jun 9, 2022
1 parent e6f1345 commit 7c5f6fe
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 7 deletions.
29 changes: 29 additions & 0 deletions src/GongSolutions.WPF.DragDrop/DragDrop.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1660,5 +1660,34 @@ public static void SetDropTargetItemsSorter(DependencyObject element, IDropTarge
{
element.SetValue(DropTargetItemsSorterProperty, value);
}

/// <summary>
/// Gets or sets the mouse move triggerd by timer
/// </summary>
public static readonly DependencyProperty MouseMoveTimerTriggeredProperty
= DependencyProperty.RegisterAttached("MouseMoveTimerTriggered",
typeof(bool),
typeof(DragDrop),
new PropertyMetadata(false));

/// <summary>Helper for getting <see cref="MouseMoveTimerTriggeredProperty"/> from <paramref name="element"/>.</summary>
/// <param name="element"><see cref="DependencyObject"/> to read <see cref="MouseMoveTimerTriggeredProperty"/> from.</param>
/// <remarks>Gets the mouse move triggerd by timer.</remarks>
/// <returns>MouseMoveTimerTriggeredProperty property value.</returns>
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static bool GetMouseMoveTimerTriggered(DependencyObject element)
{
return (bool)element.GetValue(MouseMoveTimerTriggeredProperty);
}

/// <summary>Helper for setting <see cref="MouseMoveTimerTriggeredProperty"/> on <paramref name="element"/>.</summary>
/// <param name="element"><see cref="DependencyObject"/> to set <see cref="MouseMoveTimerTriggeredProperty"/> on.</param>
/// <param name="value">SetMouseMoveTimerTriggered property value.</param>
/// <remarks>>Gets the mouse move triggerd by timer.</remarks>
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static void SetMouseMoveTimerTriggered(DependencyObject element, bool value)
{
element.SetValue(MouseMoveTimerTriggeredProperty, value);
}
}
}
4 changes: 2 additions & 2 deletions src/GongSolutions.WPF.DragDrop/DragDrop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -639,8 +639,8 @@ private static void DoDragSourceMove(object sender, Func<IInputElement, Point> g
DragDropPreview?.Move(getPosition(DragDropPreview.PlacementTarget));
}

hookId = MouseHelper.HookMouseMove(point =>
{
hookId = MouseHelper.HookMouseMove(DragDrop.GetMouseMoveTimerTriggered(dragInfo.VisualSource),
point => {
DragDropPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropPreview.PlacementTarget, point));
DragDropEffectPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropEffectPreview.PlacementTarget, point));
});
Expand Down
40 changes: 35 additions & 5 deletions src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,56 @@ internal static class MouseHelper

private const int WH_MOUSE_LL = 14;

private static bool _TimerTriggerd;
private static IntPtr _hookID = IntPtr.Zero;
private static Action<System.Windows.Point> _mouseMoveHandler;

// wee need to keep the variable to prevent the GarbageCollector to remove the HookCallback
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/68fdc3dc-8d77-48c4-875c-5312baa56aee/how-to-fix-callbackoncollecteddelegate-exception?forum=netfxbcl
private static LowLevelMouseProc _proc = HookCallback;
private static System.Windows.Threading.DispatcherTimer _timer;

internal static IntPtr HookMouseMove(Action<System.Windows.Point> mouseMoveHandler)
internal static IntPtr HookMouseMove(bool TimerTriggerd, Action<System.Windows.Point> mouseMoveHandler)
{
_mouseMoveHandler = mouseMoveHandler;
_TimerTriggerd = TimerTriggerd;

using (var process = Process.GetCurrentProcess())
if (_TimerTriggerd)
{
using (var module = process.MainModule)
_timer = new System.Windows.Threading.DispatcherTimer(System.Windows.Threading.DispatcherPriority.Input);
_timer.Tick += (sender, args) =>
{
return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(module.ModuleName), 0);
POINT lpPoint;
if (GetCursorPos(out lpPoint))
_mouseMoveHandler?.Invoke(new System.Windows.Point(lpPoint.x, lpPoint.y));
};
_timer.Interval = new TimeSpan(1);
_timer.Start();

return IntPtr.Zero;
}
else
{
using (var process = Process.GetCurrentProcess())
{
using (var module = process.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(module.ModuleName), 0);
}
}
}
}

internal static void RemoveHook(IntPtr hookId)
{
UnhookWindowsHookEx(hookId);
if (_TimerTriggerd)
{
_timer.Stop();
}
else
{
UnhookWindowsHookEx(hookId);
}
}

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
Expand Down Expand Up @@ -88,5 +115,8 @@ private struct MSLLHOOKSTRUCT

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetCursorPos(out POINT lpPoint);
}
}
2 changes: 2 additions & 0 deletions src/Showcase/Views/ListBoxSamples.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultEffectDataTemplate="True"
dd:DragDrop.MouseMoveTimerTriggered="True"
ItemsSource="{Binding Data.Collection1}" />
<ListBox x:Name="RightBoundListBox"
Grid.Column="1"
Grid.Row="0"
dd:DragDrop.DropTargetAdornerBrush="Coral"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.MouseMoveTimerTriggered="True"
dd:DragDrop.ShowAlwaysDropTargetAdorner="True"
ItemsSource="{Binding Data.Collection2}" />

Expand Down

0 comments on commit 7c5f6fe

Please sign in to comment.