この掲示板の内容にはふさわしくないかもしれませんが、質問します。
「他のアプリのテキスト入力部分に、クリップボードの内容を貼り付ける」
というEXEを、Delphiで作成しようとしているのですが、他のアプリで
キャレットを持っているコンポーネントのハンドルを、取得できなくて
困っています。
EnumChildWindowsでアクティブなウィンドウのコンポーネントを列挙し、
FindWindowExでTEditクラスと等しかったら、そのコンポーネントに内容を
貼り付ける・・・という処理をすれば、メモ帳等の特定のアプリには
貼り付けられます。
しかしテキスト部分を複数もち、かつテキスト部分を持つコンポーネントの
クラスが不明な、メモ帳以外の他のアプリに対してはできませんでした。
そこで現在キャレットを持っているコンポーネントのハンドルを、取得する
ことはできないかと考えたのですが、その方法が分かりませんでした。
どなたか教えて頂けないでしょうか。お願いします。
キャレットってフォーカスと考えていいのであれば
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に応答してくれないとテキストは拾えないですが...
ローカル変数宣言してなかった。ははっ
下記のコードではメモ帳に対してはうまくできませんでした・・・
よくわかりません・・・
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;
いい加減ですいません。
今度はメモ帳で試しました。
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;
> 他のアプリのテキスト入力部分に、クリップボードの内容を貼り付ける
この目的のためにはフォーカスをもつコントロールのハンドルはいりません。
第一、ウェブブラウザの中のコントロールのようにウィンドウレスコントロール
である場合もありますし。たんに Ctrl+V キー入力をプログラムで実行する
だけです。WM_SETTEXT に応答しないコントロールでも Ctrl+V に応答するもの
は多いです。
そうか、貼り付けが目的ということですか。
てっきり取得の方法かと思ってました。
anoneさんの手動のイベントでよければCtrl+Vです。
が”現在キャレットを持っているコンポーネントのハンドル”の取得はあれでできると思います。
> 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);
フォーカスを与えたすべてにメッセージを送信しているわけですから、不用意に書き換えてしまう恐れがあります。そこのところ工夫あれ。
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;
ありがとうございました。本当に参考になりました。
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;
これは、どのような処理を意味しているのかが分かりません。
もし宜しければ、これも教えて頂けないでしょうか。
お願いします。
たとえば空のメモ帳が対象で一度書き込んだ内容を何度も書き込むことのないようにしたまでです。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;
返事が遅くなってすいません。
理解できました。
ありがとうございました。
ツイート | ![]() |