LoginSignup
0
1

More than 3 years have passed since last update.

VB6でホイールマウスのイベントを捕まえる

Last updated at Posted at 2019-10-30

TL;DR

  • VB6でホイール対応を求められた場合の方法。過去記事(停止済みサービス利用)からの転載
  • 現在は不要な方法。基本的には.NETへの乗り換えを提案しましょう。用途は、極々ニッチな社内アプリケーションなどで今さら追加で求められた場合などのみ

概要

VB 6(Visual Basic)ではホイールのイベント(ホイール回転、ホイールボタン押下など)を標準では捕まえることができない。(.NETでは標準機能)
こちらをWindow Messageを利用して捕まえることができるようにしてみた。

使用方法

FormのLoadとUnloadに少々コードを書くことで、イベントを捕まえることができる

注意点

サブクラス化を利用しているので、デバッグモード中に停止させたりすると IDEごと落ちることがある(Form_Unload、Class_Terminateイベントが実行されない)。

ソース

clsWheelMouse.cls
'@(s)
'
' 概要:    ホイールのイベントをつかまえるクラス
'
' 備考:    宣言文:        本クラスは、WithEventsをつけて、メンバ変数で宣言して
'                           使用します。
'                           ex) Private WithEvents m_CWheel As clsWheelMouse
'
'           初期化の手順:  Form_Loadにて本クラスのインスタンスを作成し、
'                           Initializeプロシージャを呼び出し、ボタンを捕まえたい
'                           コントロールのハンドルを渡す
'                           ex) Set m_CWheel = New clsWheelMouse
'                               Call m_CWheel.Initialize(picView.hWnd)
'
'           後始末の手順:  Form_UnloadにてTerminateプロシージャを呼び出し、
'                           インスタンスの削除を行う
'                           ex) m_CWheel.Terminate
'                               Set m_CWheel = Nothing
'

Option Explicit

' [イベント]
Public Event MouseWheel(ByVal iniVector As Integer)
    '' iniVector:   -1;ホイールが奥に回転した場合
    ''               1;ホイールが手前に回転した場合
Public Event MouseWheelButtonUp(ByVal X As Single, ByVal Y As Single)
Public Event MouseWheelButtonDown(ByVal X As Single, ByVal Y As Single)
    '' XとYはTwipsで返却される

' [変数]
Private m_OwnerhWnd As Long '' イベントを捕まえるフォーム、もしくはコントロール
Private m_Initlalized As Boolean    '' 初期化されたか

Public Property Get OwnerhWnd() As Long
    OwnerhWnd = m_OwnerhWnd
End Property

Public Function Initialize(ByVal inlOwnerhWnd As Long) As Boolean
    Initialize = False

    '' ガード条件
    If m_Initlalized Then Exit Function
    If inlOwnerhWnd = 0 Then Exit Function

    m_OwnerhWnd = inlOwnerhWnd
    If Not WheelClassInitialise(Me, m_OwnerhWnd) Then Exit Function

    '' 初期化成功
    m_Initlalized = True
    Initialize = True
End Function

Public Function Terminate()
    Call WheelClassTerminate(m_OwnerhWnd)
    SetWindowLong m_OwnerhWnd, GWL_WNDPROC, _
                GetWindowLong(m_OwnerhWnd, GWL_USERDATA)
    m_Initlalized = False
End Function

Private Sub Class_Initialize()
    m_OwnerhWnd = 0&
    m_Initlalized = False
End Sub

Private Sub Class_Terminate()
    If Not m_Initlalized Then Exit Sub

    '' 終了処理が終わっていない場合には、終了処理を呼び出す
    Call Terminate
End Sub

Public Sub raiseMyEvent(ByVal iniOption As Integer, _
            ByVal iniVector As Integer, ByVal insX As Single, ByVal insY As Single)
    Select Case iniOption
        Case 1: RaiseEvent MouseWheelButtonDown(insX, insY)
        Case 2: RaiseEvent MouseWheelButtonUp(insX, insY)
        Case 3: RaiseEvent MouseWheel(iniVector)
    End Select
End Sub
modWheelMouse.bas
' @(s)
'
' 概要:    ホイール標準モジュール。ホイールクラスとセットで使用
'

Option Explicit

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
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
            (ByVal hWnd As Long, _
            ByVal nIndex As Long) _
            As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
            (ByVal hWnd As Long, _
            ByVal nIndex As Long, _
            ByVal dwNewLong As Long) _
            As Long

Public Const GWL_WNDPROC = (-4)
Public Const GWL_USERDATA = (-21)

Private Const WM_LBUTTONDOWN = &H201;
Private Const WM_LBUTTONUP = &H202;
Private Const WM_MBUTTONDOWN = &H207;
Private Const WM_MBUTTONUP = &H208;
Private Const WM_RBUTTONDOWN = &H204;
Private Const WM_RBUTTONUP = &H205;
Private Const WM_MOUSEWHEEL = &H20A;

Private m_ColCWhell As Collection

Public Function WheelClassInitialise(ByRef inoWheel As clsWheelMouse, _
                                        ByVal inlOwnerhWnd As Long) As Boolean
    Dim i As Long

    WheelClassInitialise = False

    If m_ColCWhell Is Nothing Then
        Set m_ColCWhell = New Collection
    End If

    '' ガード条件:ハンドルが0の場合は終了
    If inlOwnerhWnd = 0 Then Exit Function
    '' ガード条件:既に同じハンドルが登録されている場合には、終了
    For i = 1 To m_ColCWhell.Count
        If m_ColCWhell(i).OwnerhWnd = inlOwnerhWnd Then
            Exit Function
        End If
    Next i

    m_ColCWhell.Add inoWheel

    SetWindowLong inlOwnerhWnd, GWL_USERDATA, _
                SetWindowLong(inlOwnerhWnd, GWL_WNDPROC, AddressOf SubClassProc)

    WheelClassInitialise = True
End Function

Public Sub WheelClassTerminate(ByVal inlOwnerhWnd As Long)
    Dim i As Long

    If m_ColCWhell Is Nothing Then Exit Sub

    For i = 1 To m_ColCWhell.Count
        If m_ColCWhell(i).OwnerhWnd = inlOwnerhWnd Then
            m_ColCWhell.Remove i
            Exit For
        End If
    Next i
End Sub

Private Function SubClassProc(ByVal hwndx As Long, _
                                ByVal uMsg As Long, _
                                ByVal wParam As Long, _
                                ByVal lParam As Long) As Long
    Dim i As Long
    Dim Index As Long
    Dim zDelta As Integer
    Dim sngX As Single
    Dim sngY As Single
    Dim intHiWord As Integer
    Dim intLowWord As Integer

    If m_ColCWhell Is Nothing Then Exit Function
    If m_ColCWhell.Count = 0 Then Exit Function

    Static Calling As Boolean
    If Not Calling Then
        Index = 0
        For i = 1 To m_ColCWhell.Count
            If m_ColCWhell(i).OwnerhWnd = hwndx Then
                Index = i
                Exit For
            End If
        Next i
        If Index <> 0 Then
            Calling = True
            Select Case uMsg
            Case WM_MBUTTONDOWN, WM_MBUTTONUP   '' 中ボタンをDownもしくはUp
                '' ダブルワードを分割
                Call DWordToWord(lParam, intHiWord, intLowWord)
                '' 上位ワードがY座標:ピクセルをTwipsに変換
                sngY = CSng(intHiWord) * Screen.TwipsPerPixelY
                '' 下位ワードがX座標
                sngX = CSng(intLowWord) * Screen.TwipsPerPixelX
                If (uMsg = WM_MBUTTONDOWN) Then
                    m_ColCWhell(i).raiseMyEvent 1, 0, sngX, sngY
                Else
                    m_ColCWhell(i).raiseMyEvent 2, 0, sngX, sngY
                End If

            Case WM_MOUSEWHEEL  '' Wheelを回した
                zDelta = CInt(wParam / 2 ^ 16)
                If zDelta < 0 Then
                    '' ホイールが奥に回転した場合
                    m_ColCWhell(i).raiseMyEvent 3, -1, 0, 0
                Else
                    '' ホイールが手前に回転した場合
                    m_ColCWhell(i).raiseMyEvent 3, 1, 0, 0
                End If
            End Select
        End If
        Calling = False
    End If
    SubClassProc = CallWindowProc(GetWindowLong(hwndx, GWL_USERDATA), _
                hwndx, uMsg, wParam, lParam)
End Function

' @(f)
'
' 機能:ダブルワードを上位ワードと下位ワードに分割
'
Private Sub DWordToWord(ByVal inlDoubleWord As Long, _
                        ByRef iniHiWord As Integer, _
                        ByRef iniLowWord As Integer)
    If (inlDoubleWord And &HFFFF;&) > &H7FFF; Then
        iniLowWord = (inlDoubleWord And &HFFFF;&) - &H10000;
    Else
        iniLowWord = inlDoubleWord And &HFFFF;&
    End If

    iniHiWord = (inlDoubleWord And &HFFFF0000;) \ &H10000;
End Sub
frmMain.frm
Option Explicit

Private WithEvents m_CWheel As clsWheelMouse

Private Sub Form_Load()
    Set m_CWheel = New clsWheelMouse
    Call m_CWheel.Initialize(picMain.hWnd)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    m_CWheel.Terminate
    Set m_CWheel = Nothing
End Sub

Private Sub m_CWheel_MouseWheel(ByVal iniVector As Integer)
    lblView.Caption = "MouseWheel"
End Sub

Private Sub m_CWheel_MouseWheelButtonDown(ByVal X As Single, ByVal Y As Single)
    lblView.Caption = "MouseWheelButtonDown " & X & ";" & Y
End Sub

Private Sub m_CWheel_MouseWheelButtonUp(ByVal X As Single, ByVal Y As Single)
    lblView.Caption = "MouseWheelButtonUp " & X & ";" & Y
End Sub
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1