1

I want to create a simple mouse pointer highlighter. A circle centered at the mouse pointer. It must be semi-transparent and visible everywhere (in and out of my application).

Any idea is appreciated.

Example:

enter image description here

Xel Naga
  • 826
  • 11
  • 28
  • Actually, this is a pure Win32 question that has nothing to do with Delphi in particular; the answer would be the same in C++, for instance. – Andreas Rejbrand Jun 09 '22 at 22:33
  • 3
    Anyhow: A very simple approach would be to create a semi-transparent window and have it track the cursor. – Andreas Rejbrand Jun 10 '22 at 02:16
  • 3
    Create a `TForm` with a background color and a yellow circle on it. Set the Form's `TransparentColor` and `AlphaBlend` properties as needed. Then use a timer, or a Win32 hook, to move the `TForm` around the screen wherever the mouse cursor currently is. – Remy Lebeau Jun 10 '22 at 04:07

1 Answers1

6

Although I believe this question is a bit too broad for Stack Overflow, I cannot resist writing this short answer, because it is not only easy -- but surprisingly easy -- to make a primitive implementation of this using almost nothing but the VCL.

The idea is to have a semi-transparent, borderless form (window) that follows the mouse cursor. An ordinary TTimer updates the form's position many times each second.

Create a new VCL application. In addition to your main form, also create another form, MouseDiscForm, with the following properties:

object MouseDiscForm: TMouseDiscForm
  AlphaBlend = True
  AlphaBlendValue = 127
  BorderStyle = bsNone
  ClientHeight = 64
  ClientWidth = 64
  Color = clWhite
  TransparentColor = True
  TransparentColorValue = clWhite
  FormStyle = fsStayOnTop
  object Shape1: TShape
    Align = alClient
    Brush.Color = clYellow
    Pen.Style = psClear
    Shape = stCircle
  end
end

Override the form's CreateParams method:

procedure TMouseDiskForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_LAYERED or WS_EX_TRANSPARENT;
end;

Then in your main form, simply add a TTimer with Interval = 50 and this OnTimer handler:

procedure TForm6.Timer1Timer(Sender: TObject);
begin
  var CP := Mouse.CursorPos;
  SetWindowPos(
    MouseDiscForm.Handle,
    HWND_TOPMOST,
    CP.X - MouseDiscForm.Width div 2,
    CP.Y - MouseDiscForm.Height div 2,
    0,
    0,
    SWP_SHOWWINDOW or SWP_NOSIZE or SWP_NOACTIVATE
  );
end;

I am sure there are a few additional details one has to consider, but generally I do find this very primitive approach to work quite well.

Screen recording

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • 2
    FYI, the `WS_EX_LAYERED` window style is handled by the Form's `TransparentColor...` and `AlphaBlend...` properties, so you don't need to enable it manually in `CreateParams()`. Also, why would you put the `TTimer` on the MainForm and not on the `TMouseDiskForm` itself? – Remy Lebeau Jun 10 '22 at 15:25
  • @RemyLebeau `CreateParams` however is needed in older Delphi versions, like D7 (and so is `GetCursorPos()`). – AmigoJack Jun 15 '22 at 15:52
  • @AmigoJack the `AlphaBlend...` and `TransparentColor...` properties were added to `TForm` in D/CB 6, so only code for D/CB 5 and earlier would have to resort to enabling `WS_EX_LAYERED` manually in order to call `SetLayeredWindowAttributes()` directly. Either way, `TMouse.CursorPos` existed in D/CB 5, maybe even earlier. – Remy Lebeau Jun 15 '22 at 19:33
  • @RemyLebeau Yes, the properties. But the compiled program eats every click without overriding `CreateParams()` - compile it yourself in D7 because I did so. Yes, I can verify: in D5 `TMouse.CursorPos` exists (and simply wraps `Windows.GetCursorPos()`). – AmigoJack Jun 15 '22 at 20:59
  • 1
    You must add `WS_EX_TRANSPARENT` in every version of Windows and VCL I know of. But @Remy is right that `WS_EX_LAYERED` is superfluous. – Andreas Rejbrand Jun 15 '22 at 21:03
  • @AmigoJack "*the compiled program eats every click without overriding `CreateParams()`*" - As it should be. Just because a window is alpha-blended/translucent does not mean it is not clickable. What you are suggesting requires only `WS_EX_TRANSPARENT` be added (which has nothing to do with alpha/translucency) so that clicks fall-through the window. Just be [aware of its gotchas](https://devblogs.microsoft.com/oldnewthing/20121217-00/?p=5823). Making `WM_NCHITTEST` return `HTTRANSPARENT` would be another option. – Remy Lebeau Jun 15 '22 at 21:03