Home > Mobile >  How to make transparent Form get mouse enter events?
How to make transparent Form get mouse enter events?

Time:03-20

I want to create a Delphi application that does something interesting when the user moves his mouse over the top-left corner of the screen. I thought about it and plan to do it with the following strategy:

  1. Create a very small 3x3 Form and make it transparent and always on top. Also make it with no title bar or border.

  2. Define mouse enter event for the Form.

I use the following code for step 1:

procedure TopLeftForm.FormCreate(Sender: TObject);
begin
  FormStyle := fsStayOnTop;

  self.TransparentColor := true;
  self.TransparentColorValue := self.Color;
  self.BorderStyle := bsNone;
end;

The problem is that I found that when the Form is transparent, it can't capture mouse enter events. I could make the Form not transparent in order to get mouse enter events, but that way users can see the Form at the top-left screen corner, which is not what I want.

What's your suggestions to my problem?

CodePudding user response:

What you want is a 'Hook' that can give you information about mouse events without the events being intended for your program. It's too big a topic to be able to give you a how-to in one go, but these two links should be helpful:

Understanding how to use Windows Hooks

Mouse Hook Tutorial with Delphi codes

Why use a Windows Hook?

The Windows environment is designed around messages being passed around. Typically, a program is only interested in messages that are sent directly to its own windows. Trying to make sure that your application has a window that will get the messages blocks other applications from receiving those messages when they are in the same location under yours, and if another window is over yours then you won't get the messages. If you want to know about activity that's happening that wouldn't normally be sent to you - for example, a mouse click outside of your application's window. To enable applications to have visibility of events that are not destined for itself, a windows hook can be used.

There are different types of hooks, depending on what you want to access. A mouse hook is appropriate for what you have specified here. The system maintains a 'Hook Chain' for all of the hooks that have been installed - it will be your responsibility to pass the messages on down the chain, and to uninstall yourself from the chain.

To access the messages, your hook function will look something like this (code taken from the 2nd link above and adapted):

function MouseHookHandler(ACode: Integer; WParam: WParam; LParam: LParam): LResult; stdcall;
var
  vMouseInfo: PMouseHookStruct;
begin
  if ACode < 0 then
    Result := CallNextHookEx(Data^.MouseHook, ACode, WParam, LParam)
  else
  begin
    vMouseInfo := PMouseHookStruct(Pointer(LParam));
    PostMessage(Data^.AppHandle, WM_CUSTOM_MOUSE, vMouseInfo^.pt.X, vMouseInfo^.pt.Y);
    // we dont want to block the mouse messages
    Result := CallNextHookEx(nil, ACode, WParam, LParam);
  end;
end;

In your hook function:

  • ACode is dependent on the type of hook and indicates the event

  • wParam and lParam have a meaning specific to the event

To pass the message on, you should call CallNextHookEx - however for some hooks, the message will always be passed on regardless.

Hooks can be installed as Global hooks - meaning they intercept messages on all threads running in the same Desktop / WinStation as the calling thread. So, if you have multiple users connected via RD, for example, the hook is specific to one of those desktops only.

  • Related