Search code examples
delphiclipboarddelphi-xe7

How to detect clipboard text changes?


How can my application receive a notification when the clipboard text changes?

For example:

I would to enable/disable a paste button and setting its Hint property in order to display the clipboard's text (like 'Paste "%s"')

unit Unit1;

interface

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

type
  TMyPasteForm = class(TForm)
    MyPasteButton: TButton;
    MyEdit: TEdit;
    procedure MyPasteButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure SyncMyPasteButton();
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MyPasteForm: TMyPasteForm;

implementation

{$R *.dfm}

uses
  Clipbrd;

procedure TMyPasteForm.FormCreate(Sender: TObject);
begin
  MyPasteButton.ShowHint := True;
end;

procedure TMyPasteForm.MyPasteButtonClick(Sender: TObject);
begin
  MyEdit.Text := Clipboard.AsText;
end;

procedure TMyPasteForm.SyncMyPasteButton();
begin
  MyPasteButton.Enabled := Length(Clipboard.AsText) > 0;
  MyPasteButton.Hint := Format('Paste "%s"', [Clipboard.AsText]);
end;

end.

Solution

  • I've found an interesting PDF arcticle and edited my example accordingly with the "Using the clipboard listener API" section of the article:

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
    
    type
      TMyPasteForm = class(TForm)
        MyPasteButton: TButton;
        MyEdit: TEdit;
        procedure MyPasteButtonClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        procedure SyncMyPasteButton();
        procedure WMClipboardUpdate(var Msg : TMessage); message WM_CLIPBOARDUPDATE;
      protected
        procedure CreateWnd(); override;
        procedure DestroyWnd(); override;
      public
        { Public declarations }
      end;
    
    var
      MyPasteForm: TMyPasteForm;
    
    implementation
    
    {$R *.dfm}
    
    uses
      Clipbrd;
    
    procedure TMyPasteForm.FormCreate(Sender: TObject);
    begin
      MyPasteButton.ShowHint := True;
    
      SyncMyPasteButton();
    end;
    
    procedure TMyPasteForm.CreateWnd();
    begin
      inherited;
      //making sure OS notify this window when clipboard content changes
      AddClipboardFormatListener(Handle);
    end;
    
    procedure TMyPasteForm.DestroyWnd();
    begin
      //remove the clipboard listener
      RemoveClipboardFormatListener(Handle);
      inherited;
    end;
    
    procedure TMyPasteForm.MyPasteButtonClick(Sender: TObject);
    begin
      MyEdit.Text := Clipboard.AsText;
    end;
    
    procedure TMyPasteForm.SyncMyPasteButton();
    begin
      MyPasteButton.Enabled := IsClipboardFormatAvailable(CF_TEXT);
    
      if(MyPasteButton.Enabled) then
        MyPasteButton.Hint := Format('Paste "%s"', [Clipboard.AsText])
      else
        MyPasteButton.Hint := '';
    end;
    
    procedure TMyPasteForm.WMClipboardUpdate(var Msg : TMessage);
    begin
      //the clipboard content is changed!
      SyncMyPasteButton();
    end;
    
    end.
    

    Note:

    • It works for Windows Vista and later.

    • If you need to support Windows XP and earlier you must use a clipboard viewer approach (See the "Using the clipboard viewer chain" section of the previously mentioned article. See also SetClipboardViewer() and Monitoring Clipboard Contents)