キャレットを持っているコンポーネントのハンドルを取得するには?

解決


しゅう  2005-07-25 08:38:33  No: 16540

この掲示板の内容にはふさわしくないかもしれませんが、質問します。

「他のアプリのテキスト入力部分に、クリップボードの内容を貼り付ける」
というEXEを、Delphiで作成しようとしているのですが、他のアプリで
キャレットを持っているコンポーネントのハンドルを、取得できなくて
困っています。

EnumChildWindowsでアクティブなウィンドウのコンポーネントを列挙し、
FindWindowExでTEditクラスと等しかったら、そのコンポーネントに内容を
貼り付ける・・・という処理をすれば、メモ帳等の特定のアプリには
貼り付けられます。
しかしテキスト部分を複数もち、かつテキスト部分を持つコンポーネントの
クラスが不明な、メモ帳以外の他のアプリに対してはできませんでした。

そこで現在キャレットを持っているコンポーネントのハンドルを、取得する
ことはできないかと考えたのですが、その方法が分かりませんでした。
どなたか教えて頂けないでしょうか。お願いします。


篠田雅夫  2005-07-27 01:17:33  No: 16541

キャレットってフォーカスと考えていいのであれば

procedure TForm1.Timer1Timer(Sender: TObject);
var
  ThisWH: HWND;
  wc: TWinControl;
  buf: array[0..1000] of char;
begin
  Timer1.Enabled := false;
  wd := GetFocusInAnotherProcess;
  selfID := GetCurrentThreadID;
  wh := GetForegroundWindow;
  otherID := GetWindowThreadProcessID(wh, @prcID);
  if AttachThreadInput(otherID, selfID, True) then begin
    SetForegroundWindow(wh);
    ThisWH := GetFocus;
    AttachThreadInput(otherID, selfID, False);
    SendMessage(wd, WM_GETTEXT, 1000, Integer(@buf[0]));
    Edit1.Text := string(buf);
  end
  else Edit1.Text := '';
  Timer1.Enabled := true;

end;

WM_GETTEXTに応答してくれないとテキストは拾えないですが...


篠田雅夫  2005-07-27 01:19:47  No: 16542

ローカル変数宣言してなかった。ははっ


deldel  2005-07-27 01:47:16  No: 16543

下記のコードではメモ帳に対してはうまくできませんでした・・・
よくわかりません・・・

function GetFocusInAnotherProcess: HWND;
var
  hWin: HWND;
  TID, PID, MyID: Integer;
begin
  MyID := GetCurrentThreadID;
  hWin := GetForegroundWindow;
  TID := GetWindowThreadProcessID(hWin, @PID);
  if AttachThreadInput(TID, MyID, True) then begin
    SetForegroundWindow(hWin);
    Result := GetFocus;
    AttachThreadInput(TID, MyID, False);
  end else begin
    Result := 0;
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  wh, wd, ThisWH: HWND;
  wc: TWinControl;
  buf: array[0..1000] of char;
  selfID, otherID, prcID: DWORD;
begin
  buf := 'ABCDEFG';
  Timer1.Enabled := false;
  wd := GetFocusInAnotherProcess;
  selfID := GetCurrentThreadID;
  wh := GetForegroundWindow;
  otherID := GetWindowThreadProcessID(wh, @prcID);
  if AttachThreadInput(otherID, selfID, True) then begin
    SetForegroundWindow(wh);
    ThisWH := GetFocus;
    AttachThreadInput(otherID, selfID, False);
    SendMessage(wd, WM_GETTEXT, 1000, Integer(@buf[0]));
    Edit1.Text := StringReplace(string(buf), #0, '', [rfReplaceAll]);
  end else begin
    Edit1.Text := '';
  end;
end;


篠田雅夫  2005-07-27 02:21:01  No: 16544

いい加減ですいません。
今度はメモ帳で試しました。

procedure TForm1.Timer1Timer(Sender: TObject);
var
  ThisWH, selfID, wh, otherID, prcID, wd: HWND;
  buf: array[0..1000] of char;
begin
  Timer1.Enabled := false;
  selfID := GetCurrentThreadID;
  wh := GetForegroundWindow;
  otherID := GetWindowThreadProcessID(wh, @prcID);
  if AttachThreadInput(otherID, selfID, True) then begin
   SetForegroundWindow(wh);
    ThisWH := GetFocus;
    AttachThreadInput(otherID, selfID, False);
    SendMessage(ThisWH, WM_GETTEXT, 1000, Integer(@buf[0]));
    Edit1.Text := string(buf);
  end
  else Edit1.Text := '';
  Timer1.Enabled := true;

end;


anone  2005-07-27 02:28:46  No: 16545

> 他のアプリのテキスト入力部分に、クリップボードの内容を貼り付ける

この目的のためにはフォーカスをもつコントロールのハンドルはいりません。
第一、ウェブブラウザの中のコントロールのようにウィンドウレスコントロール
である場合もありますし。たんに Ctrl+V キー入力をプログラムで実行する
だけです。WM_SETTEXT に応答しないコントロールでも Ctrl+V に応答するもの
は多いです。


篠田雅夫  2005-07-27 06:32:49  No: 16546

そうか、貼り付けが目的ということですか。
てっきり取得の方法かと思ってました。
anoneさんの手動のイベントでよければCtrl+Vです。

が”現在キャレットを持っているコンポーネントのハンドル”の取得はあれでできると思います。


anone  2005-07-27 07:50:44  No: 16547

> anoneさんの手動のイベントでよければCtrl+Vです。

手動ではなくコードで実行するのですが

  keybd_event(VK_CONTROL,0,0,0);
  keybd_event(Ord('V'),0,0,0);
  keybd_event(Ord('V'),0,KEYEVENTF_KEYUP,0);
  keybd_event(VK_CONTROL,0,KEYEVENTF_KEYUP,0);


篠田雅夫  2005-07-27 18:56:51  No: 16548

フォーカスを与えたすべてにメッセージを送信しているわけですから、不用意に書き換えてしまう恐れがあります。そこのところ工夫あれ。

procedure TForm1.Timer1Timer(Sender: TObject);
var
  ThisWH, selfID, wh, otherID, prcID, wd: HWND;
  buf: array[0..1000] of char;
begin

  Timer1.Enabled := false;
  selfID := GetCurrentThreadID;
  wh := GetForegroundWindow;
  otherID := GetWindowThreadProcessID(wh, @prcID);
  if AttachThreadInput(otherID, selfID, True) then begin
   SetForegroundWindow(wh);
    ThisWH := GetFocus;
    AttachThreadInput(otherID, selfID, False);
    SendMessage(ThisWH, WM_GETTEXT, 1000, Integer(@buf[0]));
    if 'abc' <> string(buf) then begin
      buf := 'abc';
      SendMessage(ThisWH, WM_SETTEXT, 3, Integer(@buf[0]));
    end;
  end;
  Timer1.Enabled := true;

end;


しゅう  2005-07-28 10:57:27  No: 16549

ありがとうございました。本当に参考になりました。
anoneさんの「Ctrl+V キー入力をプログラムで実行する」方法も
篠田雅夫さんの「ハンドルを取得する」方法も両方実行できました。

anoneさんのご指摘のように、コンポーネントにはCtrl+Vに
応答するものが多いので、手動のイベントでCtrl+Vを行うのが良いか
と思いました。
しかし、現在貼り付けを行うタイミングとして、「Alt + Q」押下時
を考えていまして(ホットキーに登録)、そうすると手動のイベントでは
できないので、篠田雅夫さんの方法でハンドルを取得することにしました。

また、篠田雅夫さんのご指摘の箇所で以下についてですが、
    if 'abc' <> string(buf) then begin
      buf := 'abc';
      SendMessage(ThisWH, WM_SETTEXT, 3, Integer(@buf[0]));
    end;
これは、どのような処理を意味しているのかが分かりません。
もし宜しければ、これも教えて頂けないでしょうか。
お願いします。


篠田雅夫  2005-07-28 16:14:26  No: 16550

たとえば空のメモ帳が対象で一度書き込んだ内容を何度も書き込むことのないようにしたまでです。abcのところを'うんこ'と書き換えてもOKです。

    //bufに対象のテクストを読み込む
    SendMessage(ThisWH, WM_GETTEXT, 1000, Integer(@buf[0]));
    //bufが'abc'でなければ
    if 'abc' <> string(buf) then begin
      //bufにabcを代入して
      buf := 'abc';
      //対象のテクストに書き込む
      SendMessage(ThisWH, WM_SETTEXT, 3, Integer(@buf[0]));
    end;


しゅう  2005-08-04 07:51:51  No: 16551

返事が遅くなってすいません。
理解できました。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加