Chris Hubbard
Chris Hubbard

Reputation: 55

Delphi FindVCLWindow returning nil

My application uses mouse wheel scrolling in a number of places.

Thus I’ve written a mouse wheel handler, and this handler works out where the mouse is located before calling the appropriate object method.

On most PCs this works fine, but I have one laptop here where it does not. Despite the handler receiving the correct mouse co-ordinates from Windows, calls to FindVCLWindow are returning nil. This is however only happening when I use the laptop’s internal touch pad. External USB mice work fine.

I’ve updated the laptop’s touch pad driver to the latest available from the manufacturer's web site, but to no avail.

How else can I fix this?

Here’s the code:

unit Mouse_Wheel_Testing;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Grids;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    StringGrid1: TStringGrid;
    Mouse_Coordinates: TEdit;
    Control_Name: TEdit;
    Button1: TButton;
    procedure MouseWheelHandler(var Message: TMessage); override;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.MouseWheelHandler(var Message: TMessage);
var
  Target_Control: TWinControl;
begin
  with TWMMouseWheel(Message) do
  begin
    Mouse_Coordinates.Text := IntToStr(XPos) + ', ' + IntToStr(YPos);
    Target_Control := FindVCLWindow(Point(XPos, YPos));
    if Target_Control <> nil then
      Control_Name.Text := Target_Control.Name
    else
      Control_Name.Text := 'nil';
  end;
end;

end.

Upvotes: 0

Views: 530

Answers (1)

Chris Hubbard
Chris Hubbard

Reputation: 55

The reason why FindVCLWindow was returning nil was that WindowFromPoint was returning an incorrect handle. This in turn was the result of a setting in the laptop relating to the behavior of its touch pad when in scrolling mode. This option needed to be set correctly for the correct handle to be returned.

Since my application cannot rely on the user having their laptop set correctly, I have now written a new FindComponent function which is based upon ChildWindowFromPointEx. The following function now resides within the mouse wheel handler:

function Find_Control: TWinControl;
var
  Parent: HWND;
  Child: HWND;
  Position: TPoint;
begin { Find_Control }
  Result := nil;
  Parent := Self.Handle;
  with TWMMouseWheel(Message) do
    Position := ScreenToClient(Point(XPos, YPos));
  Child := ChildWindowFromPointEx(Parent, Position, CWP_SKIPINVISIBLE);
  while (Child <> 0) and (Child <> Parent) do
  begin
    Result := FindControl(Child);
    Position := Point(Position.X - Result.Left, Position.Y - Result.Top);
    Parent := Child;
    Child := ChildWindowFromPointEx(Parent, Position, CWP_SKIPINVISIBLE);
  end; { while (Child <> 0) and (Child <> Parent) }
end; { Find_Control }

Upvotes: 1

Related Questions