00 Votes

Delphi: GetCursorPos problem on Windows 8.1 with scaling

Question by Guest | 2015-07-19 at 04:14

I have an application which is written in Delphi 5 and has been working well for years.

I now have a problem on systems running windows 8.1 with high definition screens where scaling is set higher than 100%.

Part of the application allows the user to select the color of individual pixels on an image.

To make it easier I use a zoom box which displays a zoomed section of the main image.

When the cursor is over the main image, a smaller zoomed image with a crosshair is displayed.

When screen scaling is active, the zoom box no longer displays the area surrounding the cursor position but rather seems to be relative to the 0,0 point of the screen.

Here is the code I am using.

procedure TAutoFillForm.Timer1Timer(Sender: TObject);
var
  Srect, Drect, DisplayArea: TRect;
  iWidth, iHeight, DmX, DmY: Integer;
  iTmpX, iTmpY: Real;
  C: TCanvas;
  hDesktop: Hwnd;
  CursorPosition, ImageLoc: TPoint;
  Col, CrossHairCol: TColor;
  MaxWidth, MaxHeight, iTop, iLeft: Integer;
  DC: HDC;
  ImageRect:Trect;
begin

  If not IsIconic(Application.Handle) then begin
    hDesktop:=GetDesktopWindow;

    GetCursorPos(CursorPosition);

    ImageLoc:=Image1.ClientToScreen(Point(0,0));
    // Label9.Caption:= 'Cursor X = ' + 
    // IntToStr(CursorPosition.x) + 
    // ' : Cursor Y = ' + IntToStr(CursorPosition.Y) + 
    // ' : ScreenDPI = ' + IntToStr(ScreenDPI) + 
    // ' DPI = ' + IntToStr(Screen.PixelsPerInch) + 
    // ' Image X = ' + IntToStr(ImageLoc.x) + 
    // ' Image Y = ' + IntToStr(ImageLoc.y);

    MaxWidth:=Image1.Width;

    MaxHeight:=Image1.Height;

    DisplayArea:=Rect(ImageLoc.x,ImageLoc.y,
                ImageLoc.x+MaxWidth,ImageLoc.y+MaxHeight);


    If (PtInRect(DisplayArea,CursorPosition)) 
          and (CheckBox2.Checked) then
    begin


      If Image2.Visible=False then Image2.Visible:=True;

      iWidth:=Image2.Width;
      iHeight:=Image2.Height;
      Drect:=Rect(0,0,iWidth,iHeight);

      iTmpX:=iWidth / (TrackBar1.Position * 4 );
      iTmpY:=iHeight / (TrackBar1.Position * 4);

      GetCursorPos(CursorPosition);
      Srect:=Rect(CursorPosition.x,CursorPosition.y,
                  CursorPosition.x,CursorPosition.y);

      InflateRect(Srect,Round(iTmpX),Round(iTmpY));
  
      // move Srect if outside visible area of the screen
      If Srect.Left<0 then OffsetRect(Srect,-Srect.Left,0);
      If Srect.Top<0 then OffsetRect(Srect,0,-Srect.Top);
      If Srect.Right>Screen.DesktopWidth then 
         OffsetRect(Srect,-(Srect.Right-Screen.DesktopWidth),0);
      If Srect.Bottom>Screen.DesktopHeight then 
         OffsetRect(Srect,0,-(Srect.Bottom-Screen.DesktopHeight));


      C:=TCanvas.Create;

      try
        C.Handle:=GetDC(0);

        Image2.Canvas.CopyRect(Drect,C,Srect);
      finally
        ReleaseDC(hDesktop, C.Handle);
        C.Free;
      end;

      If CheckBox2.Checked=True then begin // show crosshair
        with Image2.Canvas do begin
          DC := CreateDC('DISPLAY',nil,nil,nil);
          Col := GetPixel(DC,CursorPosition.X,CursorPosition.Y);
          DeleteDC(DC);
          // set color to be visible over current area
          CrossHairCol:=MainForm.VisibleContrast(Col); 
          Image2.Canvas.Pen.Color:= CrossHairCol;

          DmX:=TrackBar1.Position * 2 * (CursorPosition.X-Srect.Left);
          DmY:=TrackBar1.Position * 2 * (CursorPosition.Y-Srect.Top);
          MoveTo(DmX - (iWidth div 8),DmY); // -
          LineTo(DmX + (iWidth div 8),DmY); // -
          MoveTo(DmX,DmY - (iHeight div 8)); // |
          LineTo(DmX,DmY + (iHeight div 8)); // |
        end; // with image1.Canvas
      end; // show crosshair
      Application.ProcessMessages;
    end // Cursor not inside area
    else begin // cursor inside area
      If Image2.Visible=True then Image2.Visible:=False;
    end;
  end; // IsIconic
end;

Thanks in advance for your help.

ReplyPositiveNegative
00 Votes

What do you mean with "seams to be relative to the 0,0 point of the screen"?

I can imagine that you have to use a factor for the right pixel position. When the image is scaled, a normal pixel from before is more than one 100 percent pixel. So, perhaps, you have to read out the scale factor and adjust this to display the right position.

By the way, you are talking about Windows 8.1. Have you also tested the scaling on other Windows versions?
2015-07-20 at 02:21

ReplyPositive Negative
Reply

Related Topics

Delphi: System-Wide HotKey

Tutorial | 1 Comment

Important Note

Please note: The contributions published on askingbox.com are contributions of users and should not substitute professional advice. They are not verified by independents and do not necessarily reflect the opinion of askingbox.com. Learn more.

Participate

Ask your own question or write your own article on askingbox.com. That’s how it’s done.