以编程方式模拟鼠标拖动

Posted

技术标签:

【中文标题】以编程方式模拟鼠标拖动【英文标题】:Simulate Mouse Drag Programmatically 【发布时间】:2012-10-25 14:42:12 【问题描述】:

我有一个带有控件的 Windows 窗体应用程序。该控件由一个图表面板和一个我在其上绘制的画布组成。我想做的是以编程方式鼠标拖动面板,以便在画布的右边缘和画布上绘制的最后一个项目之间有一个特定的距离。我尝试了两种方法。两者都可以根据需要拖动面板,但我似乎无法获得我想要的运动精度。我编写了一个鼠标模拟器并尝试了两种方法。

方法一:

 if(this.ChartControl.ChartPanel.CanFocus)
 
      // ... Focus the chart panel to be adjusted.
      this.ChartControl.ChartPanel.Focus();

      // ... Move cursor to lastBarScreenCoordinates on the chart panel to be adjusted.
      Cursor.Position = new Point(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);

      MouseSimulator.SetMouseDragThresholds();

      // ... Move chart panel to required position.
      MouseSimulator.LeftMouseButtonDown(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);
      MouseSimulator.MouseMove(lastBarScreenCoordinates.X-positionShift,
           lastBarScreenCoordinates.Y);
      MouseSimulator.LeftMouseButtonUp(lastBarScreenCoordinates.X-positionShift,
           lastBarScreenCoordinates.Y);

      MouseSimulator.ResetMouseDragThresholds(_cx_default, _cy_default);

      // ... Redraw the chart panel.
      this.ChartControl.ChartPanel.Refresh();

      // ... Reset cursor to its starting position.
      Cursor.Position = new Point(startingCursorX, startingCursorY);
 

方法二:

 if(this.ChartControl.ChartPanel.CanFocus)
 
      // ... Focus the chart panel to be adjusted.
      this.ChartControl.ChartPanel.Focus();

      // ... Move cursor to lastBarScreenCoordinates on the chart panel to be adjusted.
      Cursor.Position = new Point(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);

      MouseSimulator.SetMouseDragThresholds();

      // ... Move chart panel to required position.
      MouseSimulator.LeftMouseButtonDown(lastBarScreenCoordinates.X, lastBarScreenCoordinates.Y);
      Cursor.Position = new Point(lastBarScreenCoordinates.X-positionShift,
           lastBarScreenCoordinates.Y);
      WindowsCommunication.SendMessage(this.ChartControl.Handle, 0x200, IntPtr.Zero,IntPtr.Zero);
      MouseSimulator.LeftMouseButtonUp(lastBarScreenCoordinates.X-positionShift,
           lastBarScreenCoordinates.Y);

      MouseSimulator.ResetMouseDragThresholds(_cx_default, _cy_default);

      // ... Redraw the chart panel.
      this.ChartControl.ChartPanel.Refresh();

      // ... Reset cursor to its starting position.
      Cursor.Position = new Point(startingCursorX, startingCursorY);
 

我正在使用 SendInput 来模拟鼠标点击。这是示例鼠标左键按下代码...

 public static void LeftMouseButtonDown(int x, int y)
 
      INPUT mouseInput = new INPUT();
      mouseInput.type = SendInputEventType.InputMouse;
      mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x);
      mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y);
      mouseInput.mkhi.mi.mouseData = 0;
      mouseInput.mkhi.mi.time = 0;
      mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
      SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
 

我计算鼠标的归一化绝对坐标如下...

 private static int CalculateAbsoluteCoordinateX(int x)
 
      return ((x * 65536) + GetSystemMetrics(SystemMetric.SM_CXSCREEN) - 1) /
           GetSystemMetrics(SystemMetric.SM_CXSCREEN);
 

所以这里是精度问题。如果我使用方法 1(鼠标移动),最后绘制的项目与画布右边缘之间的测量距离与我在 positionShift 中设置的距离不同,并且光标位置差异不等于 positionShift。我最初认为这是由于指针弹道问题,所以我尝试使用方法 2。方法 2 确实给了我指针定位的精确度,但我仍然在面板移动但最后绘制的条与右边缘之间的距离方面遇到困难。画布不等于应有的 positionShift 量。它似乎总是关闭。我已经为此工作了很长时间,并且不知所措。我不确定这里发生了什么。如何通过模拟鼠标拖动来提高画布拖动的精度?

【问题讨论】:

这有什么意义?直接在画布上绘制即可。 这是对现有应用程序的附加,因此我无法控制最后一个元素的绘制位置。我正在尝试拖动面板而不是在其上绘制。 【参考方案1】:

您可以做的是,首先我相信 SendInput API 允许使用 AbsoluteValue 标志,因此无需计算那些可能是问题但很可能不是问题的值。

虽然我很好奇您为什么要为此使用鼠标拖动操作。似乎您想要做的就是在每次绘制时将画布重新定位一定数量。如果是这种情况,为什么不直接在画布本身上明确设置它。此外,不清楚您使用的是纯 WinForms 还是 WPF。我相当肯定 Canvas 的不清楚之处仅适用于启用 WPF 的窗口。

话虽如此 WPF修复, 根据包含画布的对象,只需根据情况适当地设置其边距,因为我不知道您正在使用的数据,所以对此我不能多说。但这是一个相对简单的想法,所以如果可行,请告诉我,它应该给你,至少也接近,像素完美对齐。

WinForms, 只需对您所说的“Canvas”对象执行上述操作,或使用对象的绝对坐标来移动它。

如果您能提供一份您正在研究的大致样子的样本,也许我们可以更好地理解您的意思。

【讨论】:

感谢您的回复。在方法 1,MouseMove 中,我确实使用了 ABSOLUTE 标志。我发现方法 1 甚至不如方法 2 精确。我将此归因于指针弹道问题。关于其他项目。这是 Winforms 而不是 WPF。我已经在这两种方法中使用绝对坐标进行移动。边距不起作用,因为虽然我可以重置它,但它会阻止绘制到我需要做的边距区域。我对你重新定位画布的建议很感兴趣。你能建议我如何在 WinForms 中做到这一点吗?谢谢。

以上是关于以编程方式模拟鼠标拖动的主要内容,如果未能解决你的问题,请参考以下文章

向父母发出传播模拟鼠标事件(拖动目的)的问题

Java Selenium Actions模拟鼠标拖动dragAndDrop总结

我可以在 JavaScript 中用鼠标模拟文本选择吗?

python模拟鼠标拖动教程

模拟鼠标拖动事件 PyQt5

python模拟鼠标拖动操作的方法