DDE でサーバにコマンドを送るものを作っています。
DDE サーバの受けられるコマンドの種類によって違うのかも知れませんが、
取り敢えず今困っているのは、コマンドを送ると、自アプリから、サーバ・アプリへ
フォーカスが奪われてしまい、困ってます。
具体的には、
・文字をEdit1 にキーから入力。
・Edit1Change(Sender: TObject);ルーチンで DDE コマンド発行。
次にキーを叩くと、サーバアプリにフォーカスがある(ウィンドウのタイトルバーが
自アブリからそちらに移っている)ので、サーバアプリが
入力文字を受けてしまって、Edit1 に連続して入力できません。
そこで、このルーチンの最後に自アプリの Edit1 (あるいは自フォーム)にずっと
自アプリにフォーカスを当てるようなコードを書くと良さそうなのですが、
いろいろ試してみてうまく行きません。
DDE クライアント・・というのは少し特殊な状況かと思いますので、
・自アプリから他のアプリにフォーカスを行かなくする方法、または、
・他のアプリにフォーカスがある時に、自アプリの Edit1 で
キー入力を受け付けられる方法
このあたりで、何かご教示いただければ嬉しいのですが・・。
キー一つタイプするたびに自アプリのフォームをクリックする・・その操作をしないで
済ませたいのです。
よろしくお願いいたします。
DDE 云々は無視して、例えば自アプリを立てて、デスクトップとかのアイコンを
クリックすると、フォーカスが自分から離れて、そのアイコンに移りますが、
その時に、「自分にフォーカスを取り戻す方法」でも構いません。
問題の焦点は DDE とは直接の関係はないと思います。
よろしくお願いいたします。
windowsでは「自分にフォーカスを取り戻す方法」は大変お行儀の悪い動作
とされているようです。そのため、win2k以降?からSetForegrandWindowでも
フォーカスは奪取されず、ただ点滅するだけになりました。
まぁ確かに急に出現する他アプリは作業の妨げになりそうですもんね。
そのため、できることなら別案を選択されるのがよいとは思いますが、
もちろん実現不可能な動作ではありません。
AttachThreadInputをキーワードに色々調べてみてください。
↓こんなのがヒットするはずです。
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=075116
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=062447
もにゃさん、返答ありがとうございました。
下のリンクは、雰囲気、「前面/背面/Zオーダ」みたいで、ざっとしかみてません(自アプリ、fsStayOnTop )ですが、上段のリンクにあった関数をやってみました。
でもダメでした。
procedure TForm1.FormDeactivate(Sender: TObject);
begin
SetForceForegroundWindow(Handle);
end;
これも入れてみましたが・・。
引数は自フォーム・ハンドルでいいんですよね?
fsStayOnTop はともかく、今回の場合でも行儀が悪い云々があてはまるのでしょうか?
操作する側(クライアント)
操作される側(サーバ)
・・ですから、操作する側が主体的でなければ・・・な感じなんですけどね。
こちらの操作中に、アクティブ(フォーカス)を奪われる訳ですから・・。
逆に、今回のこととは別に、自フォームのフォーカスを(タイマーとかでも)放す方法なんてあるのでしょうか?
それが解かれば、ひょっとするとヒントになるかも・・・な気もしますが。
>もにゃさん、返答ありがとうございました。
>下のリンクは、雰囲気、「前面/背面/Zオーダ」みたいで、ざっとしかみてません...
おやおや、せっかくの的確なアドバイスをムシするなんて...そんな態度じゃ先が思いやられる...
奪われたキーボードフォーカスを自アプリに戻すには、AttachThreadInput関数は必須。
紹介されたSetForceForegroundWindow関数をタイマーで呼び出したら目的は達成できるよ。
でも、他のアプリへのキー入力は一切出来なくなるから確かに「お行儀が悪い」かな?
オツムもメタボ?さん、ヒントありがとうございます。
>>下のリンクは、雰囲気、「前面/背面/Zオーダ」みたいで、ざっとしかみてません...
>おやおや、せっかくの的確なアドバイスをムシするなんて...そんな態度じゃ先が思いやられる...
>奪われたキーボードフォーカスを自アプリに戻すには、AttachThreadInput関数は必須。
・・・と言うか、例のサンプル関数内でAttachThreadInput が使用されていたので、これだな・・・と思った次第で・・・。
>紹介されたSetForceForegroundWindow関数をタイマーで呼び出したら目的は達成できるよ。
単独テストするとタイマーでできました。
どうやら、自アプリ処理での入れるタイミングが悪かったような雰囲気です。
>でも、他のアプリへのキー入力は一切出来なくなるから確かに「お行儀が悪い」かな?
タイマーの Enabled がずっと True だと確かにまずいですね。
これは、コマンド発行するたびに、「ワンショット・タイマー(TTL だとSN74121 相当)」に
すればいい訳で・・。
それ以外の操作だと、Timer1.Enabled := False; にしておけば特に問題なさそうですが・・・。
まぁ、入れる位置をいろいろ変えて、どうしてもダメならタイマーで・・・ってとこで解決します。
ありがとうございました。
# 当方ボディはメタボですが、オツムは、骨粗しょう症ならぬ、
#「脳細胞粗しょう症」なのでハズレです。
ここにもコピらせていただいてますが
http://delfusa.main.jp/delfusafloor/opensource/delfusalibrary/20070828160200/WindowUnit/WindowUnit.pas.txt
Torry's Delphi Pages
http://www.swissdelphicenter.ch/torry/showcode.php?id=261
こちらに、より強力っぽい。(実際は同じかな?)
関数があります。
不要かもしれませんが
いちおう、ご紹介しておきます。
Fusaさん、情報ありがとうございます。
環境配慮してあるようですね。より汎用性が高まるかも知れません。
問題発生時には役立ちそうです。
どうもありがとうございました。
既に解決済みのようですが、参考までに、
http://homepage2.nifty.com/Mr_XRAY/Delphi/plSamples/T_HookCBTCreate.htm
http://homepage2.nifty.com/Mr_XRAY/Delphi/plSamples/T_HookCBTActivate.htm
ここで紹介している、WH_CBTというフック関数を使用すると、他のウィンドウに
フォーカス移動をできなくすることが可能です(HCBT_SETFOCUSを使用)。
ただし、最低限自分のところにはフォーカス移動しておく必要はあるでしょう。
注意 : デスクトップでの動作は未確認です。