OS上の全てのキーボードイベントを拾うには?

解決


まったりぃず  2004-11-18 19:40:10  No: 117669  IP: [192.*.*.*]

初投稿になります。
まったりぃずです。よろしくお願いいたします。
質問はタイトルの通りです。
実行環境はVB6.0を想定しています。
処理イメージとしては、
・キーボードのボタン(例えばF11)が
  押されている間だけ時間をカウントしていく。
・時間はフォームに一つテキストボックスを作成しそこに表示する。
・【難点】アクティブウィンドウに依存しない作りにする。
  (作成したフォームに依存した作りなら簡単なのですが..)
以上です。
ご指導のほどよろしくお願いいたします。(^^;

編集 削除
Say  2004-11-18 20:41:44  No: 117670  IP: [192.*.*.*]

F11の押下を拾いたいだけなら、
グローバルホットキーを使ってください。(難易度低)

任意のキーを拾いたいなら
グローバルキーフックしてください。(難易度中)

腕に自信があるなら、DDKでキー監視ドライバを作って、
直接I/Oを監視することも可能かと。(難易度高)

編集 削除
まったりぃず  2004-11-19 09:59:26  No: 117671  IP: [192.*.*.*]

>Sayさん
ご回答ありがとうございます^^
ホットキーという言葉を知らなかったため
調べてみました。
これは便利ですね、たしかにこれを使えば
押された時に時間をカウントし始めることができそうです。
しかし、私の言葉が足りなかったかもしれませんが
これではボタンが離された時にカウントを止めるということが
できなそうです@@;
何か方法がございますでしょうか?

編集 削除
ぴろあき  2004-11-19 10:08:30  No: 117672  IP: [192.*.*.*]

非常に短い押下時間を無視してよければ、
GetKeyState(API)をループで回したり、
タイマーで使ったりすればできるんじゃないかな?

他の方法(最終的に有料のOcxを使えって事になってるけど)
http://www.int21.co.jp/pcdn/vb/noriolib/vbmag/9905/gui/

編集 削除
まったりぃず  2004-11-19 11:04:25  No: 117673  IP: [192.*.*.*]

>ぴろあきさん
ご回答ありがとうございます(^^

>非常に短い押下時間を無視してよければ、
>GetKeyState(API)をループで回したり、
>タイマーで使ったりすればできるんじゃないかな?

出来そうですね。
しかし、短い時間を無視・・というのは
「ボタンを押す→イベント開始」くらいの本当に短い時間にしたいのです。
そして、他APとの併用を考えているのでこちらのタイマーカウントに
あまりCPUを食べてほしくもありません^^;

>他の方法
これ以外に方法はないでしょうか?;;

よろしくお願いいたします。

編集 削除
sasa  2004-11-19 12:04:44  No: 117674  IP: [192.*.*.*]

>任意のキーを拾いたいなら
>グローバルキーフックしてください。(難易度中)

>腕に自信があるなら、DDKでキー監視ドライバを作って、
>直接I/Oを監視することも可能かと。(難易度高)

これに対する考えは?

編集 削除
まったりぃず  2004-11-19 13:27:27  No: 117675  IP: [192.*.*.*]

>sasaさん
ご指摘ありがとうございます。

>Sayさん
返答遅れてすいません。

>任意のキーを拾いたいなら
>グローバルキーフックしてください。(難易度中)
こちらも難易度低と同様に、
ボタンが離された時のイベントを拾えないという認識です。
間違っているでしょうか?

>腕に自信があるなら、DDKでキー監視ドライバを作って、
>直接I/Oを監視することも可能かと。(難易度高)
DDKは現状全く知識が無い&難しいとのことなので
放置してしまってました@@;  すいません。。
これから調べてみたいと思います。でも
この方法ならボタンが離されたことも監視できそうですね^^

どしどしご意見ご指摘よろしくお願いいたします。

編集 削除
sasa  2004-11-19 13:53:38  No: 117676  IP: [192.*.*.*]

グローバルフックはウィンドウメッセージを監視する事ができるので
キーダウン、キーアップの動作は拾えますよ。

適当にググッてヒットしたURLを貼っておきます
http://hp.vector.co.jp/authors/VA016117/hook.html

編集 削除
Say  2004-11-19 18:18:14  No: 117677  IP: [192.*.*.*]

フックDLLにせよドライバにせよVBでは作れません。
VC++やMASMなどを使ってください。
ねんのため。

編集 削除
ぴろあき  2004-11-20 09:34:58  No: 117678  IP: [192.*.*.*]

どこまでの精度を求めるかですよね。

タイマーのIntervalを10msec程度に設定して、
タイマーイベント内でGetKeyStateを使えば、
CPUもそれ程くわないだろうと思います。
ちなみに私の環境ではCPU使用率10%以下でした。

また、10msec以内の時間で、ボタンを押して離すという動作は、
人間には結構難しいです。
サンプルを作成して試してみればわかりますが、
かなり狙って短くボタンを押しても、検出する事ができます。
Private Sub Form_Load()
    Timer1.Interval = 10
End Sub
Private Sub Timer1_Timer()
    If (GetKeyState(&H7A) < 0) Then
        MsgBox "F11キー押下"
    End If
End Sub

残る問題は、時間カウントの精度ですが、
20msec程度のズレはありなのか、どうなのか・・・

編集 削除
ぴろあき  2004-11-20 09:53:21  No: 117679  IP: [192.*.*.*]

>ちなみに私の環境ではCPU使用率10%以下でした。
1%以下の間違いです。すみません・・・
#Win2K,CPU350MHz
#タスクマネージャーでプロセス毎のCPU使用率をチェックした場合


ついでに補足すれば、
20msecなんて、
下まで押されているキーが、上にあがるまで程度の時間です。
何に使用するか知りませんが、問題にならないと私は思います。

編集 削除
ぴろあき  2004-11-20 11:02:01  No: 117680  IP: [192.*.*.*]

作ってみました。

Private Declare Function GetKeyState Lib "User32.dll" (ByVal Key As Integer) As Long
Private Declare Function timeGetTime Lib "winmm.dll" () As Long

Private Sub Form_Load()
    Timer1.Interval = 10
End Sub

Private Sub Timer1_Timer()
Static timeFlag     As Boolean
Static startTime    As Long
Static endTime      As Long

    If (GetKeyState(&H7A) < 0) Then
        If timeFlag = False Then
            startTime = timeGetTime
        End If
        timeFlag = True
        Exit Sub
    End If
    
    If timeFlag Then
        endTime = timeGetTime
        MsgBox endTime - startTime & " mSec押下"
    End If
    timeFlag = False
End Sub

編集 削除
ぴろあき  2004-11-20 11:12:30  No: 117681  IP: [192.*.*.*]

細かいけど、
Exit SubのところはElseでつなげた方がいいね。
>    Exit Sub
>End If    
>If timeFlag Then
>    endTime = timeGetTime
>    MsgBox endTime - startTime & " mSec押下"
>End If
>timeFlag = False

Else
    If timeFlag Then
        endTime = timeGetTime
        MsgBox endTime - startTime & " mSec押下"
    End If
    timeFlag = False
End If

編集 削除
まったりぃず  2004-11-22 16:47:11  No: 117682  IP: [192.*.*.*]

>ぴろあきさん
レスが遅れて申し訳ありませんでした。。
サンプルコードまで作って頂いて、ありがとうございます><
試してみたところそれほど不自由には感じませんでした(^^

この案をベースとして活用していこうと思います!

しかし、技術者(ひよこですが。。)として
広い知識を身につけるべくしてSayさんから
ご指導頂いた内容も勉強して実装してみたいと思います(^^

お世話になったみなさま、心から感謝申し上げます。
そして少しでも読んで頂いたかたもありがとうございました^^

編集 削除
ぴろあき  2004-11-24 17:09:58  No: 117683  IP: [192.*.*.*]

もう見ていないかもだけど、
ループで回してもCPU使用率1%以下でしたよ。

Private Declare Function GetKeyState Lib "User32.dll" (ByVal Key As Integer) As Long
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Dim StopFlag As Boolean

Private Sub Form_Load()
    Show
    Call TimeCount
End Sub

Private Sub TimeCount()
Static timeFlag     As Boolean
Static startTime    As Long
Static endTime      As Long
    Do
        If (GetKeyState(&H7A) < 0) Then
            If timeFlag = False Then
                startTime = timeGetTime
            End If
            timeFlag = True
        Else
            If timeFlag Then
                endTime = timeGetTime
                MsgBox endTime - startTime & " mSec押下"
            End If
            timeFlag = False
        End If
        DoEvents
        Call Sleep(1)
        DoEvents
    Loop Until StopFlag
End Sub

Private Sub Form_Unload(Cancel As Integer)
    StopFlag = True
End Sub

編集 削除