多屏幕截图 - 定位鼠标光标

3

我有一个过程,可以截取一个显示器的屏幕截图,可选择将鼠标指针包含在快照中。原始函数仅适用于一个显示器。当绘制鼠标指针时,它目前只在主显示器上正确显示。但是,我无法弄清如何将其定位在其他任何显示器上。请参见此过程末尾的注释。

procedure ScreenShot(var Bitmap: TBitmap; const MonitorNum: Integer;
  const DrawCursor: Boolean; const Quality: TPixelFormat);
var
  DC: HDC;
  C: TCanvas;
  R: TRect;
  CursorInfo: TCursorInfo;
  Icon: TIcon;
  IconInfo: TIconInfo;
  M: TMonitor;
  CP: TPoint;
begin
  M:= Screen.Monitors[MonitorNum];
  DC:= GetDC(GetDesktopWindow);
  try
    C:= TCanvas.Create;
    try
      C.Handle:= DC;
      R:= M.BoundsRect;
      Bitmap.Width:= R.Width;
      Bitmap.Height:= R.Height;
      Bitmap.PixelFormat:= Quality;
      Bitmap.Canvas.CopyRect(Rect(0,0,R.Width,R.Height), C, R);
    finally
      C.Free;
    end;
  finally
    ReleaseDC(GetDesktopWindow, DC);
  end;
  if DrawCursor then begin
    R:= Bitmap.Canvas.ClipRect;
    Icon:= TIcon.Create;
    try
      CursorInfo.cbSize:= SizeOf(CursorInfo);
      if GetCursorInfo(CursorInfo) then
      if CursorInfo.Flags = CURSOR_SHOWING then
      begin
        Icon.Handle:= CopyIcon(CursorInfo.hCursor);
        if GetIconInfo(Icon.Handle, IconInfo) then
        begin
          CP:= CursorInfo.ptScreenPos;

          //Transition mouse position...?
          CP.X:= CP.X + M.Left;
          CP.Y:= CP.Y + M.Top;  //No difference?

          Bitmap.Canvas.Draw(
            CP.X - Integer(IconInfo.xHotspot) - R.Left,
            CP.Y - Integer(IconInfo.yHotspot) - R.Top,
            Icon);
        end;
      end;
    finally
      Icon.Free;
    end;
  end;
end;

我应该如何根据我使用的显示器正确地转换鼠标位置?
1个回答

3
您正在将屏幕坐标 MonitorRect.Left 映射到位图坐标 0 。同样, MonitorRect.Top 映射到 0 。因此,如果光标的屏幕位置为 CursorPos ,则将其映射到 CursorPos.X-MonitorRect.Left 和 CursorPos.Y-MonitorRect.Top 。然后您还需要考虑热点,但是您似乎已经知道如何做了。
上述映射对所有监视器都适用。
请注意,我使用自己的符号,因为我发现您的单个字母变量具有误导性。更不用说这些变量的含义在函数期间会发生变化。我看着你, R 。那总是带来痛苦的食谱。
另外,您是否需要删除调用 GetIconInfo 时交给您的位图句柄?一些错误检查也不会错过。

啊,好吧,应该是减号而不是加号。如果删除这两行代码,它就无法正常工作——只有在光标位于主监视器上时才会显示光标,而不是实际截图所在的监视器。 - Jerry Dodge
哦,我明白了,你两次使用了 R!R的值是位图矩形,始终锚定在0,0处。 - David Heffernan
这个值得回收利用,因为if DrawCursor then begin的开始标志着一个不同的代码块的开始。所以我把它命名为一个短名称,如“R”。 - Jerry Dodge
3
@Jerry,如果变量没有命名,而且在不同的时间具有不同的含义,会使代码更难读。这是我给你的建议。接受或不接受由你决定。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接