Windowsフォームアプリケーションにキーボードショートカットを実装する最良の方法は?


280

C#でWindowsフォームアプリケーションに一般的なWindowsキーボードショートカット(Ctrl+ FCtrl+などN)を実装する最良の方法を探しています。

アプリケーションには、多くの子フォーム(一度に1つ)をホストするメインフォームがあります。ユーザーがCtrl+ Fを押すと、カスタム検索フォームが表示されます。検索フォームは、アプリケーションで現在開いている子フォームに依存します。

ChildForm_KeyDownイベントで次のようなものを使用することを考えていました:

   if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control)
        // Show search form

しかし、これは機能しません。キーを押してもイベントは発生しません。解決策は何ですか?


WinformsがネイティブのWindows APIのように特定の機能を備えていないように見えるのは本当に奇妙です。
スチュワート

回答:


460

フォームのKeyPreviewプロパティをTrue に設定するのを忘れた可能性があります。ProcessCmdKey()メソッドのオーバーライドは一般的なソリューションです。

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    MessageBox.Show("What the Ctrl+F?");
    return true;
  }
  return base.ProcessCmdKey(ref msg, keyData);
}

これはうまく機能しますが、フォームがアクティブウィンドウである場合にのみ検出されます。誰でもそれをバインドする方法を知っているので、どのウィンドウビューでも可能です?
Gaʀʀʏ

いくつかの状況でKeyPreviewは非常に不可欠です。たとえば、入力を抑制するためにショートカットを押す必要がある場合でも、別のMenuStripイベントを発生させることができます。ProcessCmdKeyアプローチは、イベント発生ロジックの複製を強制します。
Saul

1
いいえ、フォームのKeyDownイベントハンドラは、メニュー項目のClickイベントハンドラとはまったく異なります。まったく同じ方法で、イベントハンドラーメソッドを直接呼び出すか(イベントによって排他的に呼び出される必要はありません)、共通ロジックを別のメソッドにリファクタリングします。
ハンスパッサント2014年

14
「Ctrl + Fって何?」笑
kchad

73

メインフォーム

  1. KeyPreviewTrueに設定
  2. 次のコードでKeyDownイベントハンドラーを追加します。

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }

4
+の場合、KeyPreviewをTrueに設定すると、欠落していた
Usman Younas 2013年

20

最良の方法は、メニューニーモニックを使用することです。つまり、必要なキーボードショートカットが割り当てられるメインフォームにメニューエントリを含めることです。次に、他のすべてが内部的に処理され、Clickそのメニューエントリのイベントハンドラーで実行される適切なアクションを実装するだけです。


1
問題は、メインフォームが一般的なウィンドウメニューを使用しないことです。子フォームの表示に使用されるカスタムナビゲーションパネルを使用します。検索フォームは、子フォームのToolStripButtonをクリックして呼び出されます。
Rockcoder、2008

menu mnemonics実際のサンプル?
Kiquenet


1
ニーモニックはショートカットキーとは異なる概念であり、それらの動作には重要な違いがあります。つまり、ニーモニックは、キーボードを使用してメニュー、メニューコマンド、ダイアログコントロールにアクセスするために使用される下線付きの文字です。OTOH、ショートカットキーは、メニューを介さずにコマンドにアクセスする方法です。さらに、文字キーに限定されず、Ctrl + FやF5などの任意のキーストロークを使用できます。
スチュワート

1
@Stewart正解です!私の答えは、すべてのキーボードショートカットがニーモニックであることを意味するのではなく、単にメニューニーモニックがこの機能を取得する最も簡単な方法であるということです。残念ながら、ロックコーダーのコメントが明確にするように、このソリューションはここでは適切ではないようです。可能な限り、私はそれを望ましい解決策として推奨しています。一般的な解決策としては、ハンスが受け入れた答えが先の道です。
Konrad Rudolph

11

この例を試すこともできます:

public class MDIParent : System.Windows.Forms.Form
{
    public bool NextTab()
    {
         // some code
    }

    public bool PreviousTab()
    {
         // some code
    }

    protected override bool ProcessCmdKey(ref Message message, Keys keys)
    {
        switch (keys)
        {
            case Keys.Control | Keys.Tab:
              {
                NextTab();
                return true;
              }
            case Keys.Control | Keys.Shift | Keys.Tab:
              {
                PreviousTab();
                return true;
              }
        }
        return base.ProcessCmdKey(ref message, keys);
    }
}

public class mySecondForm : System.Windows.Forms.Form
{
    // some code...
}

8

メニューがある場合は、ShortcutKeysプロパティを変更するとうまくいきますToolStripMenuItem

そうでない場合は、作成してそのvisibleプロパティをfalseに設定できます。


いいえ、メニューはありません。検索用のToolStripButtonは実際にはBindingNavigatorコントロールにあるため、メニューの追加はおそらくオプションではありません。
Rockcoder、2008

6

メインフォームから、次のことを行う必要があります。

  • KeyPreviewを必ずtrueに設定してください(デフォルトではTRUE)。
  • MainForm_KeyDown(..)を追加します。これにより、必要なショートカットをここで設定できます。

さらに、これをグーグルで見つけたので、まだ回答を探している人にこれを共有したいと思いました。(グローバル)

私はあなたがuser32.dllを使用している必要があると思います

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == 0x0312)
    {
        /* Note that the three lines below are not needed if you only want to register one hotkey.
         * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */

        Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
        KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
        int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.


        MessageBox.Show("Hotkey has been pressed!");
        // do something
    }
}

さらにこれを読んでくださいhttp://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/


4

ハンスの答えは、これを初めて使う人にとって少し簡単になるかもしれないので、これが私のバージョンです。

でバカにする必要はありません。そのKeyPreviewままにしておいてくださいfalse。以下のコードを使用するには、コードをの下に貼り付けてform1_load実行し、機能F5することを確認します。

protected override void OnKeyPress(KeyPressEventArgs ex)
{
    string xo = ex.KeyChar.ToString();

    if (xo == "q") //You pressed "q" key on the keyboard
    {
        Form2 f2 = new Form2();
        f2.Show();
    }
}

7
まず、ProcessCmdKeyのオーバーライドは、コマンドのような操作を行うことを目的としたキーストロークを処理するための推奨される方法です。これは、OPが要求していたことです。次に、KeyPreviewをtrueに設定することに関するHansのコメントを誤解しました。彼はただ彼のテクニックがうまくいかない理由をOPに伝えていた。KeyPreviewをtrueに設定することは、ProcessCmdKeyの使用には必要ありません。
RenniePet 14

2

WinFormでは、次の方法で常にコントロールキーのステータスを取得できます。

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.