[Delphi] 半透明でクリックを透過するウィンドウの作り方

# はじめに
RADStudio Users Group に[「Delphiでマウス・キーボード操作をスルーする方法はありますか？」](https://groups.google.com/g/radstudio-jp/c/3xSOIUMrsaE/m/dxxjY_5dAgAJ)という質問がありました。
そこで、この記事では VCL / FireMonkey で実現する方法を紹介します。

# VCL の場合
VCL の場合、2つのプロパティと[CreateWindowEx](https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-createwindowexw) の dwExStyle に値を設定してやるだけで簡単に実現できます。

## プロパティの設定
VCL の TForm には [AlphaBlend](https://docwiki.embarcadero.com/Libraries/ja/Vcl.Forms.TCustomForm.AlphaBlend) というプロパティと [AlphaBrendValue](https://docwiki.embarcadero.com/Libraries/ja/Vcl.Forms.TCustomForm.AlphaBlendValue) というプロパティがあります。
AlphaBlend プロパティを True にすると Form が [Layered Window](https://learn.microsoft.com/ja-jp/windows/win32/winmsg/window-features#layered-windows) という特殊なウィンドウになります。
Layered Window は半透明にしたり背景を透過したりできます。

Layered Window の半透明の度合いは AlphaBlendValue で制御できます。
AlphaBlendValue に 0 を指定すると完全に透明、255 で完全に不透明になります。

下はこのプロパティの値を変更した例です。
値によって透け具合が異なっています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/2b335693-e4b5-9d14-edb3-e401895c7e7e.png" width=400>

また、必要であれば [FormStyle](https://docwiki.embarcadero.com/Libraries/ja/Vcl.Forms.TCustomForm.FormStyle) プロパティを fsStayOnTop にして最前面ウィンドウにします。

## CreateWindowEx のカスタマイズ

CreateWindowEx のパラメータは VCL の場合簡単に変更できます。
VCL の TForm には [CreateParams](https://docwiki.embarcadero.com/Libraries/ja/Vcl.Forms.TCustomForm.CreateParams) というメソッドがあるためです。
このメソッドは CreateWindowEx を呼ぶ前にパラメータを変更する機会を提供してくれます。

そこで、このメソッドを override して ExStyle を変更します。

```delphi
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

var
  Form1: TForm1;

implementation

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;

  Params.ExStyle :=
    Params.ExStyle
    or WS_EX_TRANSPARENT // 透明化
    or WS_EX_NOACTIVATE; // アクティブにならない
end;
```

肝は WS_EX_TRANSPARENT と WS_EX_NOACTIVATE です。
Layered Window の場合、この２つを指定する事で、マウスクリックを透過します。
（Layered Window ではない場合は透過しません）

## 完成
上記の CreateParams の変更と AlphaBlend / AlphaBlendValue を設定すると完成です。
こんな風にクリックが透過します

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/9b176b96-25ac-a14e-8c5f-d74da05004bd.gif" width=600>

<details><summary>コード全文 (CreateParams があるだけ…) </summary><div>

```delphi
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;

  Params.ExStyle :=
    Params.ExStyle
    or WS_EX_TRANSPARENT // 透明化
    or WS_EX_NOACTIVATE; // アクティブにならない
end;

end.
```
</div></details>

# FireMonkey の場合
これはもう力づくです。
FormCreate で必要な Win32 API を呼んでやります。
基本は VCL と同じです。

ちなみに FireMonkey の TForm には [Transparency](https://docwiki.embarcadero.com/Libraries/ja/FMX.Forms.TCommonCustomForm.Transparency) というプロパティがあるのですが、これはフォームの背景色(Fill.Color)を透明にしてしまうので使えません。
(VCL の [TransparentColor](https://docwiki.embarcadero.com/Libraries/ja/Vcl.Forms.TCustomForm.TransparentColor) と同等)

```delphi
uses
  Winapi.Windows
  , FMX.Platform.Win
  ;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Window Handle の取得
  var HWnd := FormToHWND(Self);

  // ExStyle の取得
  var ExStyle := GetWindowLong(HWnd, GWL_EXSTYLE);

  // ExStyle に追加
  ExStyle :=
    ExStyle
    or WS_EX_LAYERED     // Layered Window
    or WS_EX_TRANSPARENT // 透明化
    or WS_EX_NOACTIVATE; // アクティブにならない

  // ExStyle を設定
  SetWindowLong(HWnd, GWL_EXSTYLE, ExStyle);

  // Layered Window の透明度を指定
  SetLayeredWindowAttributes(HWnd, 0, 128, LWA_ALPHA);

  // 必要であれば Window を最前面に
  SetWindowPos(
    HWnd,
    HWND_TOPMOST,
    0,
    0,
    0,
    0,
    SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end;
```

ということで無事 FireMonkey でもクリック透過するようになりました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/4b577e3e-22f1-e761-cf79-784d855aa2eb.gif" width=600>

# さいごに
ガジェット系のアプリを作る時にたまに使うテクニックです。
Windows オンリーのアプリになるのでわざわざ FireMonkey で作る必要は無いですね…！