Search code examples
delphimousedelphi-xe2windows-messages

How can a control receive mouse events after the mouse is dragged beyond its borders?


I'm creating a custom control which recognizes when the mouse is dragging, specifically using messages WM_LBUTTONDOWN, WM_LBUTTONUP, and WM_MOUSEMOVE. When the mouse goes down, I capture the position on the control, and then when the mouse moves, if the left mouse button is down, I do more handling (calculating between starting and ending points).

The problem is, I'm expecting the mouse to go out of the control, and even out of the form, but when the mouse leaves the control, it no longer captures mouse events. Is there a way I can handle specifically the WM_MOUSEMOVE and WM_LBUTTONUP messages without the mouse being over the control?


Solution

  • Releasecapture will work for Wincontrols, an other way could be a Mousehook. That's just a demo ....

    unit MouseHook;
    // 2012 by Thomas Wassermann
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
    
      TForm3 = class(TForm)
        procedure FormDestroy(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private-Deklarationen }
      public
        { Public-Deklarationen }
      end;
    
    var
      Form3: TForm3;
    
    implementation
    
    var
      HookHandle: Cardinal;
    
    Type
      tagMSLLHOOKSTRUCT = record
        POINT: TPoint;
        mouseData: DWORD;
        flags: DWORD;
        time: DWORD;
        dwExtraInfo: DWORD;
      end;
      TMSLLHOOKSTRUCT = tagMSLLHOOKSTRUCT;
      PMSLLHOOKSTRUCT = ^TMSLLHOOKSTRUCT;
    
    {$R *.dfm}
    
    function LowLevelMouseProc(nCode: Integer; wParam: wParam; lParam: lParam): LRESULT; stdcall;
    var
     Delta:Smallint;
    begin
      if (nCode >= 0) then
      begin
        Form3.Caption := Format('X: %d  Y: %d ', [PMSLLHOOKSTRUCT(lParam)^.Point.X,  PMSLLHOOKSTRUCT(lParam)^.Point.Y]);
        if wParam = WM_LButtonDOWN then Form3.Caption := Form3.Caption + ' LD';
        if wParam = WM_LButtonUP then Form3.Caption := Form3.Caption + ' LU';
        if wParam = WM_RButtonDOWN then Form3.Caption := Form3.Caption + ' RD';
        if wParam = WM_RButtonUP then Form3.Caption := Form3.Caption + ' RU';
        if wParam =  WM_MOUSEMOVE then Form3.Caption := Form3.Caption + ' Move';
        Delta := PMSLLHOOKSTRUCT(lParam)^.mouseData shr 16;
        if wParam =  WM_MOUSEWHEEL then
              begin
    
                Form3.Caption := Form3.Caption + ' Wheel ' ;
                if Delta=120 then Form3.Caption := Form3.Caption + ' KLICK'
                else if Delta > 0  then Form3.Caption := Form3.Caption +' UP'
                else if Delta < 0  then Form3.Caption := Form3.Caption +' DOWN'
              end;
        if wParam =  WM_MOUSEHWHEEL then
              begin
                Form3.Caption := Form3.Caption + ' HWheel';
                if Delta=120 then Form3.Caption := Form3.Caption + ' KLICK'
                else if Delta > 0  then Form3.Caption := Form3.Caption +' UP'
                else if Delta < 0  then Form3.Caption := Form3.Caption +' DOWN'
    
              end;
         Form3.Caption := Form3.Caption +' >> '+ IntToStr(Delta)
    
      end;
      Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
    end;
    
    function InstallMouseHook: Boolean;
    begin
      Result := False;
      if HookHandle = 0 then
      begin
        HookHandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseProc, hInstance, 0);
        Result := HookHandle <> 0;
      end;
    end;
    
    procedure TForm3.FormCreate(Sender: TObject);
    begin
      InstallMouseHook;
    end;
    
    procedure TForm3.FormDestroy(Sender: TObject);
    begin
      if HookHandle <> 0 then
        UnhookWindowsHookEx(HookHandle);
    end;
    
    end.