Скриншот с несколькими мониторами — позиционирование курсора мыши

У меня есть процедура, которая делает снимок экрана монитора и дополнительно включает в снимок курсор мыши. Первоначальная функция была только для одного монитора. При рисовании курсора мыши в настоящее время он правильно отображается только на главном мониторе. Но я не могу понять, как расположить его на любом другом мониторе. См. комментарии в конце этой процедуры.

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;

Как правильно изменить положение мыши в зависимости от того, какой монитор я использую?


person Jerry Dodge    schedule 02.06.2013    source источник


Ответы (1)


Вы сопоставляете координату экрана MonitorRect.Left с координатой растрового изображения 0. И так же с MonitorRect.Top по 0. Итак, если позиция курсора на экране CursorPos, вы сопоставляете ее с CursorPos.X - MonitorRect.Left и CursorPos.Y - MonitorRect.Top. А тут еще и горячую точку надо учитывать, а как это сделать вы, похоже, уже знаете.

Приведенное выше сопоставление одинаково применимо ко всем мониторам.

Обратите внимание, что я использовал свои собственные обозначения, потому что нашел ваши однобуквенные переменные неверными. Не говоря уже о том, что значение этих переменных меняется во время работы функции. Я смотрю на тебя, R. Это всегда рецепт боли.

Кроме того, вам не нужно удалять дескрипторы растровых изображений, которые передаются вам при вызове GetIconInfo? И не помешала бы некоторая проверка ошибок.

person David Heffernan    schedule 02.06.2013
comment
Ааа, ладно, + должен был стать -, который сделал это. И это не сработает, если вы удалите эти 2 строки - курсор будет отображаться только в том случае, если курсор находится на основном мониторе, но не на фактическом мониторе, на котором сделан снимок экрана. - person Jerry Dodge; 03.06.2013
comment
О, я вижу, вы использовали R дважды! Значение R — это прямоугольник растрового изображения, который всегда привязан к 0,0. - person David Heffernan; 03.06.2013
comment
Что ж, это стоило переработать, так как начало if DrawCursor then begin отмечает начало другого блока кода. Отсюда и причина, по которой я оставил ему короткое имя, такое как R. - person Jerry Dodge; 03.06.2013
comment
@Jerry Наличие переменных, которые не названы и принимают разные значения в разное время, затрудняет чтение кода. Это мой вам совет. Возьми это или оставь. - person David Heffernan; 03.06.2013