キーボードイベントを受け取るには

解決


老かも  2010-02-27 06:21:04  No: 37789

いつもお世話になります。いろいろ調べてみたのですが、判らずまた投稿させて頂きます。

1,Delphi2007+WinXPSP3です
2,メインフォーム(Form1)とフォーム2、フォーム3が自動生成設定。
3,やりたいこと:メインフォームのボタンをクリックすると、フォーム2を    Hideし、その状態でキーボードの適当なキー操作で再度フォーム2を表示す  る。
4,メインフォームのKeyPreviewをTrueにし、メインフォームに以下のコードを  実装します。

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
   if (GetKeyState(ord('Z')) < 0 )then Form2.Show;
end;

これで、メインフォームがフォーカスを持っている時は、フォーム2が表示されるのですが、フォーカスがフォーム3にある時は当然ながらキーボードイベントを受け取れません。操作する人がマウスでメインフォームをクリックすることなく、キー操作だけで、上記を実現することは出来ないのでしょうか?

よろしくお願いします。


えーと  2010-02-27 08:05:44  No: 37790

そのアプリのどこかにフォーカスがあるとき、アプリ全体でキーボードを
監視できればいいんですよね。

D6以降は持ってないので確かめられませんが、すくなくともD6では、Application.OnMessage か、Additional タブのところにある TApplicationEvents コンポの OnMessage イベントで捕まえられます。
生のメッセージですから、自分でデコードしなければなりませんが。
どなたか試してくれませんか?  実行環境がないのでわたしはできません。
すみません。


ttt  2010-02-27 08:17:31  No: 37791

Application系を使うなら、OnShortCutの方が
キーボードイベントしか来ない分扱いやすいかも。

Form1にActionListを置いてやって、アクションを一つ追加し
それのShortCutを設定するという方法もあります。

ちなみに、もし他のアプリケーションを操作中でもキーを受け取りたいという場合は
RegisterHotKeyあたりを使うことになります。


KHE00221  2010-02-27 17:24:38  No: 37792

procedure TForm3.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
   if (GetKeyState(ord('Z')) < 0 )then Form2.Show;
end;

とするだけでは・・・・


武田  2010-02-27 20:59:19  No: 37793

過去に同じ悩みを持って、どっちみちドラッグドロップも使うので
兼業させた記憶があります。
どちらが正しい使い方かわかりませんが、教えてもらったまんま。
//=======AppMessageを使う場合=======
  private
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);overload;

procedure TForm1.FormCreate(Sender: TObject);
    Application.OnMessage:= AppMessage;
    DragAcceptFiles(TreeView1.Handle, True); //ドラッグドロップも使う場合 

procedure TForm1.FormDestroy(Sender: TObject);
    Application.OnMessage := nil;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var
    FileNames:array[0..255] of Char;
    Files :Integer;
begin
    if Msg.Message = WM_DROPFILES then
    begin
        DragQueryFile(Msg.wParam, 0, FileNames, Sizeof(FileNames) - 1);
        Files := DragQueryFile(Msg.wParam, $FFFFFFFF, nil, 0);
        if (FindDragTarget(Msg.pt,False) is TTreeView) then
        begin
            for i := 0 to Files - 1 do
      begin
        {ドラッグドロップの処理}
      end;
        end;
        DragFinish(Msg.wParam);
        Handled:= True;
    end;
    if  GetAsyncKeyState(27)<>0   then
    begin
        Sleep(300);
    {キーが押された場合の処理}
    end;
end;

//======MsgHandler(を使う場合)=======
  private
  procedure MsgHandler(var Msg: TMsg; var Handled: Boolean);

procedure TForm1.FormCreate(Sender: TObject);
    DragAcceptFiles(TreeView1.Handle, True);//ドラッグドロップも使う
    Application.OnMessage := MsgHandler;

procedure TForm1.FormDestroy(Sender: TObject);
    Application.OnMessage := nil;

procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
var
    FileNames:array[0..255] of Char;
    Files :Integer;
begin
    if Msg.Message = WM_DROPFILES then
    begin
        DragQueryFile(Msg.wParam, 0, FileNames, Sizeof(FileNames) - 1);
        Files := DragQueryFile(Msg.wParam, $FFFFFFFF, nil, 0);
        if (FindDragTarget(Msg.pt,False) is TTreeView) then
        begin
            for i := 0 to Files - 1 do
      begin
        {TreeViewへのドラッグドロップの処理}
      end;
        end;
        DragFinish(Msg.wParam);
        Handled:= True;
    end;
    if  GetAsyncKeyState(27)<>0   then
    begin
        Sleep(300);
    begin
      {ESCキーキーが押されて時の処理}
        end;
    end;
end;


D  2010-02-27 22:00:35  No: 37794

こんなやり方もあるということで。

procedure TForm3.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  Form1.FormKeyDown(Sender, Key, Shift);
end;

>ちなみに、もし他のアプリケーションを操作中でもキーを受け取りたいという場合は
>RegisterHotKeyあたりを使うことになります。

  タイマーを使ってお手軽にやる場合の例。

procedure TForm1.Timer1Timer(Sender: TObject);
var
  li_Code: SHORT;
begin
  li_Code := GetAsyncKeyState(Ord('Z'));
  if (BOOL(Hi(li_Code)) and BOOL(Lo(li_Code))) then begin
    Beep;
  end;
end;


老かも  2010-03-02 00:05:10  No: 37795

皆様いろいろ情報有り難うございました。
Form3に同じコードを記述すれば良いのですが、フォームが増えていった場合には、同じコードをフォーム毎に記述するのは?と思いApplicationレベルで処理できないかと。

お陰様で解決致しました。有り難うございました。


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

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






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