WPFでホットキーコントロールが作れないかなぁと思ってコーディングしてみる。ホットキーコントロールというのは、テキストボックスのようなコントロール上でキー入力するとそのキーが表示されるというコントロールです。
見た目的にTextBoxを使ってみます。キー入力イベントはKeyDownではなく、PreviewKeyDownを使うと より多くのキーでイベントが起きるのでこっちを使います。またCtrl+CやBackSpaceなどによるテキストの編集も e.Handled = True により抑制できます。ただしマウスによるテキスト編集は対策を考えないといけません。
' XAML
' <TextBox PreviewKeyDown="TextBox_PreviewKeyDown" />
Private Sub TextBox_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs)
e.Handled = True
End Sub
入力されたキーは e.Key に格納されているのですが、これが列挙体の型になってます。つまり1個のキーの値しか入っていません。これでは複数キー入力に対応できません。でも、とりあえずそれは置いといて……。
Control・Shift・Alt・Windowsキーに関しては、Keyboard.Modifiers を使います。複数キー入力の判定もできます。ちなみに、e.Key の値では右と左の Control キーによって値が区別されていますが、ModifierKeys では違いはありません。
If CBool(Keyboard.Modifiers And ModifierKeys.Control) Then
' Control キーが押された
End If
以上でCtrl+Cという組み合わせは、
If CBool(Keyboard.Modifiers And ModifierKeys.Control) AndAlso e.Key = Key.C Then
' Ctrl + C
End If
と書けます。ここらへんまでのサンプルは検索していろいろ出てきたのですが、それ以降が見つからない。Ctrl+Cはうまくいくのですが、Alt+Cでは e.Key の内容がCではなく特殊キーを表す System という値が格納されています。
ここで、あるキーが押されているかどうかという判定に、Keyboard.IsKeyDown が使えるようです。Alt+Cのとき、e.Key = Key.C は成立しませんが、以下の条件式は成立します。
If Keyboard.IsKeyDown(Key.C) Then
' Cが押されてる
End If
というわけでイベント発生毎に IsKeyDownメソッドを使って、どのキーが押されているか判定する感じでしょうか? スマートじゃない気がするなぁ。IsKeyDown を使用して、押されているキーを表示するコードは次のようになります。さらさらーっと。
Private Sub TextBox_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs)
Dim list = New List(Of String)
For Each k As Key In [Enum].GetValues(GetType(Key))
If k = Key.None Then
Continue For
End If
If Keyboard.IsKeyDown(k) Then
list.Add(k.ToString)
End If
Next
DirectCast(sender, TextBox).Text = String.Join(" + ", list.ToArray)
e.Handled = True
End Sub
これを実行すると私の環境では、Aと入力しただけでも
HanjaMode + HanjaMode + A + DbeAlphanumeric + DbeAlphanumeric + OemAuto + OemAuto + Attn + Attn + Zoom + Zoom
といっぱい特殊なキーも押されていると表示されてしましました。なぜ同じ名前が重なっているのがよくわかりませんが……。なんにせよ、キー押下判別時のキーの種類を制限する必要がありそうです。また、このコードだとAとB同時押しも判別できますが、最終的にホットキーで登録することを考えると、ホットキーとして有効なキーの組み合わせを表示する処理も要りますね。
今日はここまで。続く?