チェックボックスのキーダウン時に矢印キーを検知する方法について
VB6のチェックボックスについて質問させて頂きます。
環境
Windows 2000 SP4
Visual Basic 6.0(SP6)
チェックボックスのキーダウン時に矢印キーを検知する方法について、ご存知の方がいらっしゃいましたら、ぜひ教えて頂きたいです。
自分なりに調べてみた結果は以下の通りです。
チェックボックスのKeyDownイベントでは矢印キーは検知できませんでした。
次に試したのが、サブクラス化を行い、WM_KEYDOWNを取得する方法です。
正直、サブクラス化を行えば矢印キーを確実に検知できると考えていたのですが、なぜか矢印キーを押してもWM_KEYDOWNメッセージを取得できず、このため矢印キーの検知ができませんでした。
矢印キー以外のキー、例えばAやSなどは問題なく検知できました。
ちなみに、この状態でSpy++を起動し、矢印キーを押したときのメッセージを確認してみると、チェックボックスウィンドウはきちんとWM_KEYDOWNを受け取っていました。
それなのにサブクラス化した方ではWM_KEYDOWNは取得できません。
まだ完全にサブクラス化の概念を理解している訳ではないため、恐らく何か原因があるのでしょうが、想像ができないでいます。
( Windowsから送られるメッセージがチェックボックスウィンドウに届くまでの間に誰がメッセージを処理してるのかが分かりません。自分は間に何もないと考えていました )。
この動作についても知っている方がいたら、説明して頂けるととても助かります。
すいませんが、ご教授お願い致します。
No.8ベストアンサー
- 回答日時:
APIで自力でチェックボックスを作成すると、KeyDownが取得できます。
その結果からVB製のチェックボックスは、VBのライブラリ中で、自前サブクラス関数より先にメッセージを捕まえ、カーソルキーであればフォーカス制御の処理を行って、メッセージを破棄していることが予想できます。
破棄されたメッセージは、捕まえようがありません。
なのでVBより先にメッセージを得るために、フックしてあげないとできないのではないかな?
下に、APIでCheckBoxを作成する方法を載せておきます。
値の変更処理とかを追加しないと、OnOffが切り替わりません。
質問者さんのサンプルに、コードの変更と追加です。
モジュール追加で以下
Option Explicit
Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal HINSTANCE As Long, lpParam As Any) As Long
Private Declare Function DestroyWindow Lib "user32" (ByVal hWnd As Long) As Long
Private Const BS_CHECKBOX = &H2&
Private Const WS_CHILD = &H40000000
Private Const WS_VISIBLE = &H10000000
Public Sub CreChk(Owner As Form)
Dim hChk As Long
hChk = CreateWindowEx(0, "Button", "チェックボックス", _
WS_CHILD Or WS_VISIBLE Or BS_CHECKBOX, _
0, 0, 150, 30, Owner.hWnd, 0&, App.HINSTANCE, 0&)
Call SubClass(hChk)
End Sub
あとそちらのサンプルの関数「WindowProc」をちょっと改造
Select Case uMsg
Case WM_KEYDOWN
Debug.Print Now & "KeyDown : KeyCode( " & wParam & " )"
Case WM_DESTROY
Call UnSubClass(hWnd)
End Select
呼び出しはフォームLoadで
Call CreChk(Me)
Unload時は不要
サブクラス関数内で、勝手に破棄
回答ありがとうございます。
あ、やばい、かぶちゃった…
すいません、先に回答して頂いてたのですね。
分かりやすい回答に、さらにサンプルまで付けて頂き、ありがとうございます。
WindowProcでWM_DESTROY拾って破棄など、とても参考になりました。
No.7
- 回答日時:
回答番号:No.6 の回答は取消させて下さい。
どうも違うメッセージを拾ってしまったようです。
回答ありがとうございます。
あ、そうでしたか。
わざわざ調査して頂きすいません、凄い助かります。
私の方でいま調査していたところ、CreateWindowExを使用し、作成したチェックボックスをサブクラス化した場合は、問題なく矢印キーを検知できることが分かりました。
確かに、VB6のチェックボックスは矢印キーでのフォーカス移動が最初から実装されているので、なんか怪しいとは感じていたのですが。
このことから、VB6のチェックボックス自体がフックなどを使用し、矢印キーの制御を実装しているかもしれませんね。
試しにいまCreateWindowExで作成したチェックボックスにキーボードフックのインストールとサブクラス化を行い、試したみたところ、VB6のコントロールと同様の動きになりました。
いま私が考えられるサブクラス化しても矢印キーを検知できなかった原因としては、これが精一杯ですね。
No.6
- 回答日時:
>サブクラス化でできないか調査している次第でした。
If uMsg = &H100E Then
If wParam = 3 Then
Debug.Print "↑"
End If
If wParam = 7 Then
Debug.Print "↓"
End If
End If
今試して見たら、uMsg = &H100E で wParam = 3 で ↑ で
wParam = 7 で ↓ が取得できるようです。
理由とかは、現在調査中、取りあえず取得出来る事だけを。
No.5
- 回答日時:
ハッキリした目的が解らないので、使えるかどうか、解りませんが
一応下記のようにすれば、矢印キーが押された事を取得できます。
Option Explicit
Private Declare Function GetKeyState Lib "user32" _
(ByVal nVirtKey As Long) As Integer
Private Sub Check1_GotFocus()
Label1.Caption = ""
End Sub
Private Sub Check1_LostFocus()
If GetKeyState(vbKeyUp) < 0 Then
Label1.Caption = "↑"
ElseIf GetKeyState(vbKeyDown) < 0 Then
Label1.Caption = "↓"
End If
End Sub
回答ありがとうございます。
あ、私も昨日ググって調べているときに、この方法を目にしました。
確かにこの方法を使えば矢印キーを取得することができるのですが、フォーカス喪失時というのが私がやろうとしていた目的に合わず、いまはサブクラス化でできないか調査している次第でした。
きちんと目的を記載せずに、すいませんでした。
No.4
- 回答日時:
回答ではありません。
目的は、何なのでしょうか?
それによっては、代替案があるかも知れません。
1個だけ位なら、ダミーのテキストボックスを使ってそちらで
取得するとか?
ピクチャーボックスでチェックボックスを作るとか。
少なくても、サブクラス化するよりは簡単かなと思いますよ。
早速のご返信、ありがとうございます。
そうですね、私もピクチャボックスでチェックボックスを作るなどの代替案を考えてみて、幾つか対応できる方法を見つけることができました。
しかし、どうしてサブクラス化をしているのに、方向キーでのWM_KEYDOWNが検知できないのかが分からず、誰か知っている人がいれば教えて頂きたいなと思いまして質問させて頂いた次第です。
No.3
- 回答日時:
参考URL
http://okwave.jp/qa/q4164908.html
SetWindowsHookEx
UnhookWindowsHookEx
CallNextHookEx
↓
フック関数「SetWindowsHookEx」
の呼び出し引数は「WH_CBT」となっているけどそこを変更して
「WH_KEYBOARD=2」
か
「WH_KEYBOARD_LL=13」
でいけるかな?
.NET用だけど、殆ど一緒です。
http://azumaya.s101.xrea.com/wiki/index.php?%B3% …
あと、不要なキーボードイベントもくるので、チェックボックスにカーソルがあるときの判定を、しなくてはいけません。
アクティブコントールのハンドルを取得するなどしてやるようにですね。
質問者さんのスキルは高そうなので、多くは言いません。
早速のご回答、ありがとうございます。
大変参考になります。
やはりフックを使用する方法しかないですよね。
記載して頂いた通り、フックは目的のコントロールを判定してやらなければならないので、できればサブクラス化でできないかなと思い、はまってしまった状態でした。
というのは、いまチェックボックスをベースにしたユーザコントロールを作成していまして、既存のチェックボックスのキーダウンイベントでは矢印キーを検知できないので、サブクラス化を利用し、矢印キーも検知できるキーダウンイベントを実装していました。
このため、好みの問題かもしれませんが、できればフックよりサブクラス化の方がしっくりくるかなと思い、現状に至っています。
ちなみに、このコントロールはグリッド専用のチェックボックスという目的で使用を考えてまして、チェックボックスなどを使用できるグリッドコントロールも同時に作成しています。
グリッドのため、方向キーでの移動を実装しなければならず、このためチェックボックスでの方向キーを検知したかったのでした。
打開策としては、フォントでチェックボックスっぽく見せる方法や、チェックボックスのコンテナをピクチャボックスとし、ちょこっと制御することで、方向キーを検知する方法などが見つかりましたが、なんでサブクラス化じゃできないかが、どうしても分からず、凄く気になってしまい、どなたか知っている方がいないかと思いまして、質問させて頂いた次第でした。
No.2
- 回答日時:
_
この回答への補足
Private Const PROPNAME As String = "OriginWindowProc"
Public Sub SubClass(hWnd As Long)
Dim DefProc As Long
DefProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
If DefProc <> 0 Then
Call SetProp(hWnd, PROPNAME, DefProc)
End If
End Sub
Public Sub UnSubClass(hWnd As Long)
Dim DefProc As Long
DefProc = GetProp(hWnd, PROPNAME)
If DefProc <> 0 Then
SetWindowLong hWnd, GWL_WNDPROC, DefProc
End If
End Sub
Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim DefProc As Long
Select Case uMsg
Case WM_KEYDOWN
Debug.Print "KeyDown : KeyCode( " & wParam & " )"
End Select
DefProc = GetProp(hWnd, PROPNAME)
If DefProc <> 0 Then
WindowProc = CallWindowProc(DefProc, hWnd, uMsg, wParam, lParam)
End If
End Function
4. イミディエイトウィンドウに押したキーが表示されるが、矢印キーは表示されないことが確認できる
5. Spy++で確認すると、WM_KEYDOWNが発生していることが確認できる
No.1
- 回答日時:
_
この回答への補足
文字数が足りないので、分割させて頂きます。
以下に自分が調査したときに使用したサブクラス化のサンプルコードを添付します。
1. プロジェクトにフォームとモジュールを追加し、フォームにチェックボックスを1つ追加する。
2. 以下コードをフォームに貼り付ける。
Option Explicit
Private Sub Form_Load()
SubClass Me.Check1.hWnd
End Sub
Private Sub Form_Unload(Cancel As Integer)
UnSubClass Me.Check1.hWnd
End Sub
3. 以下コードをモジュールに貼り付ける。
Option Explicit
Private Const GWL_WNDPROC = (-4)
Private Const WM_KEYDOWN = &H100
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( _
ByVal hWnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long _
) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" ( _
ByVal lpPrevWndFunc As Long, _
ByVal hWnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long _
) As Long
Private Declare Function SetProp Lib "user32" Alias "SetPropA" ( _
ByVal hWnd As Long, _
ByVal lpString As String, _
ByVal hData As Long _
) As Long
Private Declare Function GetProp Lib "user32" Alias "GetPropA" ( _
ByVal hWnd As Long, _
ByVal lpString As String _
) As Long
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Windows 10 フォルダ内の全ての画像を矢印キーでスライドできるようにしたい 1 2022/10/21 12:53
- Windows 10 エクスプローラで希望の場所が表示できない 2 2023/06/29 15:19
- Word(ワード) IMEパッドがショートカットキーで開かないのですが。。。 5 2023/06/11 09:23
- Excel(エクセル) Excelで、カーソルの移動が異常です。 1 2022/06/15 20:54
- 楽器・演奏 ピアノの楽譜の基本的な質問 4 2022/12/04 22:20
- Windows 10 パソコンの起動時、画面が黒いままのトラブルにつきまして。 4 2022/10/02 18:02
- その他(Microsoft Office) エクセルのマクロを教えてください。 1 2023/01/27 09:05
- YouTube YouTubeのホーム画面自動再生の際の早送り 1 2022/08/05 18:21
- ノートパソコン パソコンのキーが一つ取れて無くなりました。ボタン一つですが修理に43000円かかると言われました。右 15 2022/05/29 06:22
- マウス・キーボード キーボードのCaps Lockキーと変換キーの挙動がおかしくなりました。 4 2022/09/04 22:44
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
vbaから他のアプリを終了
-
メッセージボックスの選択ボタ...
-
SendMessage で ESC など
-
msgboxの表示位置
-
PCのシャットダウン処理
-
VB.netでFindWindowExやると・...
-
他のウィンドウのボタンを自動...
-
WINAPI 他のウインドウを重ね...
-
Excel VBA で外部アプリケーシ...
-
マウスホイールをフックしたい
-
VBA 複数セルが空白なら印刷さ...
-
マウスの右クリック+Shiftキー...
-
CloseHandle()
-
メッセージハンドラ
-
ElseIfの使い方。
-
SetWindowText関数について
-
フックをするなら逆アセンブル?
-
DEVICECHANGE() の受け取り
-
WM_CLEARなど使えないメッセー...
-
エクセルで作った新しいウイン...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
vbaから他のアプリを終了
-
msgboxの表示位置
-
他のウィンドウのボタンを自動...
-
メッセージボックスの選択ボタ...
-
SetWindowText関数について
-
VBAでコントロールのハンドルを...
-
Excel VBA で外部アプリケーシ...
-
VB.netでFindWindowExやると・...
-
メッセージハンドラ
-
点滅で知らせる方法
-
CloseHandle()
-
システム例外のメッセージを変...
-
WM_NCLBUTTONUPについて
-
デスクトップ上のアイコンの位...
-
メッセージループについて
-
キーボード・フックのアプリを...
-
VBでRegisterWindowMessage関数...
-
WM_CTLCOLORDLG
-
windowsメールスロットについて...
-
マウスフックについて
おすすめ情報