C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

コード中で押されたキーを確認する方法

[トピック内 15 記事 (1 - 15 表示)]  << 0 >>

■88699 / inTopicNo.1)  コード中で押されたキーを確認する方法
  
□投稿者/ 面白 (1回)-(2018/09/20(Thu) 22:02:05)

分類:[.NET 全般] 



VB.NETでキーボードで押されたキーの確認を行うのに
普通は、KeyDownメソッドを使いますが、
これだとキーの同時押しを認識するが難しいため
コード中で、いま矢印キーが押されたかなどを調べたいのですが
どのようにすれば良いですか?
検索しても方法が見つかりませんでしたので
よろしくお願いいたします。






引用返信 編集キー/
■88700 / inTopicNo.2)  Re[1]: コード中で押されたキーを確認する方法
□投稿者/ Jitta (412回)-(2018/09/20(Thu) 23:00:00)
No88699 (面白 さん) に返信
>

https://qiita.com/sawasaka/items/b3d5285b4198c0e46628

「リアルタイムキー入力 .net」で検索


引用返信 編集キー/
■88701 / inTopicNo.3)  Re[1]: コード中で押されたキーを確認する方法
□投稿者/ とっちゃん (527回)-(2018/09/20(Thu) 23:07:32)
No88699 (面白 さん) に返信
>
>
> VB.NETでキーボードで押されたキーの確認を行うのに
> 普通は、KeyDownメソッドを使いますが、
> これだとキーの同時押しを認識するが難しいため
> コード中で、いま矢印キーが押されたかなどを調べたいのですが
> どのようにすれば良いですか?
> 検索しても方法が見つかりませんでしたので
> よろしくお願いいたします。
>

上と左キーとか、A、Wが両方押されているかを状況に応じて検出したいということでしょうか?
お手軽という点では、System.Windows.Input.Keyboard クラスがお手軽だと思います。

C# での事例ですが、下記のブログでFormsアプリで使ってる例があります。
コード以外はVBも同じです(WPFアプリの場合は参照の追加などは不要)。
https://www.ipentec.com/document/csharp-check-keboard-key-press-state

それ以外だと、API になるんじゃないかと思います。

引用返信 編集キー/
■88706 / inTopicNo.4)  Re[2]: コード中で押されたキーを確認する方法
□投稿者/ 面白 (3回)-(2018/09/21(Fri) 09:21:25)
ありがとうございます。

http://hanatyan.sakura.ne.jp/patio/read.cgi?mode=view2&f=332&no=0
ここに書いてあるコードも参考にして
APIの方を試してみたのですが

''' <remarks></remarks>
<DllImport("User32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function GetKeyState( _
   ByVal nVirtKey As Integer) As Integer
End Function

をコードの先頭に書いた上で


        Do

            Thread.Sleep(10)

            If GetKeyState(Keys.LShiftKey) < 0 Then
                MessageBox.Show("左の Shift キーが押されました。")
            ElseIf GetKeyState(Keys.RShiftKey) < 0 Then
                MessageBox.Show("右の Shift キーが押されました。")
            End If


            If GetKeyState(Keys.Left) < 0 Then
                MessageBox.Show("左キーが押されました。")
            ElseIf GetKeyState(Keys.right) < 0 Then
                MessageBox.Show("右 キーが押されました。")
            End If


            If GetKeyState(Keys.W) < 0 Then
                MessageBox.Show("W キーが押されました。")
            ElseIf GetKeyState(Keys.a) < 0 Then
                MessageBox.Show("A キーが押されました。")
            End If


        Loop



とやって、
WやAキーなどを押してみたのですが
メッセージボックスが表示されないのですが・・・・

なぜでしょうか?






引用返信 編集キー/
■88707 / inTopicNo.5)  Re[3]: コード中で押されたキーを確認する方法
□投稿者/ 面白 (4回)-(2018/09/21(Fri) 09:29:15)
エラーメッセージは特になく
デバッグしたくとも
キーを押しながら、ブレイクできないので
どうやれば良いか分かりません
引用返信 編集キー/
■88709 / inTopicNo.6)  Re[4]: コード中で押されたキーを確認する方法
□投稿者/ Hongliang (704回)-(2018/09/21(Fri) 10:36:44)
まず、ループでキーボードの入力を監視する、という手続き的なコーディングは、GUIアプリでは基本的に不可能です。
「タイマを使って定期的に確認する」「KeyDown/KeyUpイベントなどで入力に変更があった際に他のキーの状態も確認する」などを検討してください。

いわゆるprintfデバッグをするなら、MessageBoxで表示させるのではなく、Debug.Printなどを使ってVisual Studioの出力ウィンドウ(またはイミディエイトウィンドウ)に表示させた方が良いでしょう。

https://msdn.microsoft.com/ja-jp/library/cc364676.aspx
GetKeyStateの返値はSHORT、つまり16ビット符号付き整数値です。一方、面白さんの定義では返値がInteger、つまり32ビット符号付き整数値に指定されています。
引用返信 編集キー/
■88710 / inTopicNo.7)  Re[5]: コード中で押されたキーを確認する方法
□投稿者/ 面白 (5回)-(2018/09/21(Fri) 11:40:59)
ありがとうございます。
Shortにするとうまくいきました。

http://hanatyan.sakura.ne.jp/patio/read.cgi?mode=view2&f=332&no=0

このサイトが間違ったことを書いていたのですね・・
テストしていなかったのでしょうか。

解決済み
引用返信 編集キー/
■88711 / inTopicNo.8)  Re[4]: コード中で押されたキーを確認する方法
□投稿者/ とっちゃん (529回)-(2018/09/21(Fri) 11:44:09)
No88707 (面白 さん) に返信
> エラーメッセージは特になく
> デバッグしたくとも
> キーを押しながら、ブレイクできないので
> どうやれば良いか分かりません

.NET アプリでは、ループでキーの状態を監視するプログラムを書くことができません。

なので、何かのメッセージハンドラでその都度チェックするのが一般的な対応となります。

具体的には以下が多いかな?
1. タイマー(定期的な処理に都合がいい)
2. なんらかのキーイベント
3. 何らかのマウスイベント
をトリガーにしてその都度チェックするというのが多いです。

APIの定義が間違っているという点は、すでに Hongliang さんが指摘してる通り。
具体的には、16bit値を返すのに32bit値として取り込んでしまうため
本当なら、-32767 を返しているのに、+32768 として解釈されてしまい
マイナスにならないという状況だと思います。

プライベートなメソッドとして、キーの入力チェックコードを用意し
それを、各種キーイベントやマウスなど実際のプログラム上でチェックしたいか所から呼び出してみてください。
その際、ループではなく、それぞれのキーを1回だけチェックする。
状態表示にDebug.Printを使う。
戻り値で状態を返すもしくは、プロパティ(もしくはプライベートなフィールド)に状態を格納する。
という形にし、呼び出し後の処理として必要な作業(ゲームなら移動とか)をすればいいと思います。


引用返信 編集キー/
■88712 / inTopicNo.9)  Re[6]: コード中で押されたキーを確認する方法
□投稿者/ とっちゃん (531回)-(2018/09/21(Fri) 11:45:16)
あ、入れ違いで、解決マーク消してしまった。。。
ので、再度つけておきます。

解決済み
引用返信 編集キー/
■88715 / inTopicNo.10)  Re[1]: コード中で押されたキーを確認する方法
□投稿者/ 魔界の仮面弁士 (1847回)-(2018/09/21(Fri) 12:09:33)
No88699 (面白 さん) に返信
> これだとキーの同時押しを認識するが難しいため

同時押しの数や組み合わせによっては、そもそも正しく認識できないこともあります。
(使用しているキーボードに依存)


> コード中で、いま矢印キーが押されたかなどを調べたいのですが
> どのようにすれば良いですか?

'参照設定:PresentationCore 
'参照設定:WindowsBase
Public Class Form1
    Private Labels As Dictionary(Of System.Windows.Input.Key, System.Windows.Forms.Label)
    Private View As System.Windows.Forms.FlowLayoutPanel
    Public Sub New()
        'InitializeComponent()
        Text = "白:押されていない/黄:トグル/水:押下中/緑:トグル+押下中"

        View = New System.Windows.Forms.FlowLayoutPanel()
        View.Dock = System.Windows.Forms.DockStyle.Fill
        View.AutoScroll = True
        Controls.Add(View)

        Labels = System.Enum.GetValues(GetType(System.Windows.Input.Key)) _
                .OfType(Of System.Windows.Input.Key)() _
                .Where(Function(k) k <> System.Windows.Input.Key.None) _
                .Distinct().OrderBy(Function(k) k) _
                .ToDictionary(
                    Function(k) k,
                    Function(k) New System.Windows.Forms.Label() With
                    {.Text = k.ToString("G"), .BorderStyle = BorderStyle.Fixed3D}
                )
        View.Controls.AddRange(Labels.Values.ToArray())

        AddHandler System.Windows.Forms.Application.Idle, AddressOf Application_Idle

        Size = New Size(800, 700)
    End Sub

    Private Sub Application_Idle(sender As Object, e As EventArgs)
        For Each entry In Labels
            Dim state As System.Windows.Input.KeyStates = System.Windows.Input.Keyboard.GetKeyStates(entry.Key)

            Select Case state
                Case System.Windows.Input.KeyStates.None
                    entry.Value.BackColor = Color.White
                Case System.Windows.Input.KeyStates.Toggled
                    entry.Value.BackColor = Color.Yellow
                Case System.Windows.Input.KeyStates.Down
                    entry.Value.BackColor = Color.Cyan
                Case System.Windows.Input.KeyStates.Toggled Or System.Windows.Input.KeyStates.Down
                    entry.Value.BackColor = Color.LimeGreen
                Case Else
                    entry.Value.ResetBackColor()
            End Select
        Next
    End Sub
End Class

引用返信 編集キー/
■88716 / inTopicNo.11)  Re[7]: コード中で押されたキーを確認する方法
□投稿者/ 面白 (6回)-(2018/09/21(Fri) 12:11:39)
Hongliang さんも述べていましたが
> まず、ループでキーボードの入力を監視する、という手続き的なコーディングは、GUIアプリでは基本的に不可能です。

> .NET アプリでは、ループでキーの状態を監視するプログラムを書くことができません。


これはどういうことですか?

実際に、バックグランドプロセスで
Do Loopを使えば、タイマーで行っているのと同じように
一定時間毎にキーを確認することができているので、
これで問題ないと思うのですが。

私かお二方のどちらかが何か勘違いしていますでしょうか?



引用返信 編集キー/
■88717 / inTopicNo.12)  Re[8]: コード中で押されたキーを確認する方法
□投稿者/ 魔界の仮面弁士 (1848回)-(2018/09/21(Fri) 12:25:03)
No88716 (面白 さん) に返信
> これはどういうことですか?

UI スレッドで、長時間 Return されないメソッドを呼び出してはならない、ということです。
UI を持たないバックグラウンドスレッドや、コンソールアプリケーションであれば OK です。


ただしいずれにせよ、MessageBox.Show で検査するのはまずいです。
メッセージが表示されたところで、キーボード系のメッセージ処理が
阻害されてしまう可能性が高いので、検証のための確認であれば、
Debug.WriteLine などを用いた方が良いでしょう。
引用返信 編集キー/
■88718 / inTopicNo.13)  Re[9]: コード中で押されたキーを確認する方法
□投稿者/ 面白 (8回)-(2018/09/21(Fri) 12:48:14)
No88717 (魔界の仮面弁士 さん) に返信
> ■No88716 (面白 さん) に返信
>>これはどういうことですか?
>
> UI スレッドで、長時間 Return されないメソッドを呼び出してはならない、ということです。
> UI を持たないバックグラウンドスレッドや、コンソールアプリケーションであれば OK です。
>
ありがとうございます。

納得しました。

ちなみに、
PresentationCore、WindowsBaseの方法は
DLLの設定や生成が必要になるのでできれば、APIを使いたいのですが
APIの方法と.NETの方法で、
処理速度や、機能性などに違いはございますでしょうか?

引用返信 編集キー/
■88719 / inTopicNo.14)  Re[10]: コード中で押されたキーを確認する方法
□投稿者/ とっちゃん (532回)-(2018/09/21(Fri) 17:28:54)
No88718 (面白 さん) に返信
> ちなみに、
> PresentationCore、WindowsBaseの方法は
> DLLの設定や生成が必要になるのでできれば、APIを使いたいのですが
> APIの方法と.NETの方法で、
> 処理速度や、機能性などに違いはございますでしょうか?
>

System.Windows.Input.Keyboard クラスを利用する場合、そのプロジェクトに参照設定を追加する作業が必要なだけで、何かが生成されることはありません。
ほかの製品のモジュールを使う場合と同じで、メニューから選んでいくだけなので、難しいところはないと思います。

APIを利用する場合、そのAPIを呼ぶためのプラットフォーム呼び出しコードを記述する必要があります。
これが正しく記述されていないと誤動作します(SHORTになってなくて誤動作したのはそれが原因です)。


処理速度については、System.Windows.Input.Keyboard の実装を見てみないとわからないです。
ですが、最終的にはAPIを呼び出していると思いますので、JITの分を除けば、時間差は計測誤差程度しか出ないのでは?と思います。

機能性については、System.Windows.Input.Keyboard クラスなどでほかの機能を使うか?とかそういうところも影響するため、言及できないです。

APIを使う場合ですが、
GetKeyState と GetAsyncKeyState のどちらを利用するべきかが状況で変わります(結果が変わる場合があるため。詳しくはご自身でじっくり英語リファレンスを読んでください)。

また、キー入力はフォーカスウィンドウが最速で反応できるようにOS内部で処理されます。
そのため、フォーカスウィンドウを持つUIスレッドで処理するのが安定的な処理になります。

もし、ゲームの操作など、ユーザーのキー操作への反応速度を高めたいということであれば、キーイベントをトリガーとしてUIスレッド上でチェックするのが一番最速です(.NET アプリの場合)。
APIを使う場合でもそうじゃない場合でもです。


APIが処理する時間もきちんと考慮しておかないと、速度の向上という点では意味を成しません。
このあたりは突き詰めると、.NET やめるか?という世界に行くのであまり深入りしないことをお勧めしますが。。。

引用返信 編集キー/
■88721 / inTopicNo.15)  Re[11]: コード中で押されたキーを確認する方法
□投稿者/ 魔界の仮面弁士 (1849回)-(2018/09/21(Fri) 18:03:00)
2018/09/21(Fri) 18:07:14 編集(投稿者)

No88719 (とっちゃん さん) に追記
> System.Windows.Input.Keyboard クラスを利用する場合、そのプロジェクトに参照設定を追加する作業が必要なだけで、何かが生成されることはありません。

実行環境に、.NET Framework 3.0 以降が必要にはなりますね。

とはいえ、Service Pack 1 未適用な .NET Framework 2.0 環境であるとか、
.NET Framework 1.x しかインストールされていないといった、
古い OS でも無い限り、実行にあたって、追加のインストール作業が
必要になることも無いでしょう。



> ですが、最終的にはAPIを呼び出していると思いますので、

System.Windows.Input.Keyboard クラスの実装を確認したところ、
GetKeyState / IsKeyDown / IsKeyUp / IsKeyToggled メソッドは、
内部的には GetKeyState API の呼び出しとして実装されていました。


> もし、ゲームの操作など、
DirectInput という選択肢もありますね。
協調レベルを指定することで、自アプリがアクティブでない場合にも
キー入力をイベントとして捉えることができます。


ただし、複数のキーボードが接続されていて、それぞれを個別に
認識したいような場合は、GetKeyState API や DirectInput でも拾えないので、
Raw Input を使う必要がありそうです。
https://docs.microsoft.com/ja-jp/windows/desktop/inputdev/raw-input

RawInput を扱うためのライブラリは、nuget などで入手できますが、
追加のライブラリの利用を嫌うのであれば、GetKeyState API 同様に、
自前で Declare/DllImport して呼び出すこともできます。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ