c# ショートカットキーを正しく処理するには? (その2)

そこそこ、複雑なアプリケーションで、ショートカットキーを正しく処理する方法は意外に難解です。単純なアプリケーション用のより簡単な方法は c# ショートカットキーを正しく処理するには? (その3) をご覧ください。

利用しやすい解決方法

この方法は、c# ショートカットキーを正しく処理するには? (その1) にくらべると、コードのわかりやすさでは劣りますが、使いやすいかもしれません。

アプリケーション全体のショートカット (その1と共通)

ショートカットキーは、Form の ToolStripMenuItemShortcutKeys で指定します。デザイナーでビジュアルに指定できるので簡単です。この方法では、修飾子なしのショートカットキーが指定できないので、それらのキーは、Form の ProcessCmdKey をオーバーライドして処理します。ProcessCmdKey で処理を打ち切る場合には、true を、続ける場合には、base.ProcessCmdKey を呼び、その値を返します。

ShortcutKeys で指定したキーは、base.ProcessCmdKey で処理されます。メニューに処理させない場合やできない場合に、テキストだけ表示させるには、ShortcutKeyDisplayString を使います。

処理を続ける場合のサンプルコード

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
  if (keyData == Keys.Escape) // ESC 単独
    Clipboard.Clear();

  return base.ProcessCmdKey(ref msg, keyData);
}

フォーカスに依存したショートカット (その1と共通)

アプリケーションが複数のビューからなり、フォーカスのあるビューによってショートカットの挙動を変えるには、各ビューのメニューや、ProcessCmdKey に Form と同様の処理を書けば OK です。

フォーカスのあるコントロールの ProcessCmdKey が最初に呼ばれるため、フォーカスにより挙動を変化させることができます。base.ProcessCmdKey により、親の ProcessCmdKey が呼ばれ、最終的には、 Form の ProcessCmdKey が呼ばれます。

コンボボックスにおける注意点 (Ctrl+V など)

例えば、ショートカットキーに Ctrl+V を使用している場合、ProcessCmdKey により、コンボボックス本来の機能がオーバーライドされます。コンボボックスフォーカス時に、本来の動作を行わせるには、以下のようにします。

コンボボックスの、 PreviewKeyDown イベントで、キーを調べ、Ctrl+V などで、 PreviewKeyDownEventArgs.IsInputKey を true に設定します。true に設定すべきキーは、Ctrl+C、Ctrl+V、Ctrl+X、Ctrl+Z、Ctrl+Insert、Shift+Insert、Shift+Delete、Alt+Back です。

Ctrl や Shift などの修飾の無いアクセラレーターキーを定義したい場合には、修飾子が無い場合、F1〜F24、Escape 以外で、true を設定すると良いでしょう。

また、Ctrl+A はディフォルトでは処理されないようですが、ここで SelectAll() してから、true を返すことで実現できます。

その他コントロールでの注意点

コンボボックスだけでなく、コントロールで必要なキーをショートカットキーで使用している場合には、それらのコントロールの PreviewKeyDown イベントでも同様の処理を行います。

他の方法との比較

その1との比較

その1 では、コンボボックスで本来の挙動を行うために、コンボボックスの派生クラスを作って、ProcessCmdKey をオーバーライドしています。派生クラスを作成する分、コードは増えますが、再利用性は高いと言えます。

こちらの方法でも、 PreviewKeyDown イベントの代わりに、 OnPreviewKeyDown メソッドを使うことで、再利用性を高めることは可能ですが、ProcessCmdKey を利用した方が、一貫性があるのでよりわかりやすいと思います。

派生しなくても、イベントハンドラをライブラリ化して、結びつけて使えば再利用性は高まりますね。あんまり美しくはありませんが、現実的にはよい方法かもしれません。

IsInputKey との違い

IsInputKey は、PreviewKeyDown の PreviewKeyDownEventArgs.IsInputKey と似てますが、挙動がかなり違います。

PreviewKeyDown は、 PreProcessMessage よりも先に呼ばれ、引数の IsInputKey を true に設定すると、 PreProcessMessage、ProcessCmdMessage、ProcessDialogMessage は呼ばれません。

一方、IsInputKey では、true を返すと、ProcessDialogMessage は呼ばれなくなりますが、ProcessCmdMessage は呼ばれます。

となりのページ

このサイトについて

このサイトのページへのリンクは自由に行っていただいてかまいません。
このサイトで公開している全ての画像、プログラム、文書の無断転載を禁止します。

連絡先

ここをクリック すると表示されるページから作者へメールで連絡できます。

共有