|
||
|
Detecting Mouse XButton ClicksRecently I discovered that my mouse had two strange buttons on the left-hand side (until then I'd thought that the mouse's case just wasn't very well put together). Turns out these are the 'X Buttons' and can be used for moving backwards and forwards in Explorer and IE. This sample demonstrates how you can intercept clicks on these buttons to provide the same functionality in a VB application. Intercepting XButton MessagesXButton clicks are sent to a Window in a similar way as the more traditional mouse button actions are. There are six XButton messages; the first group is for mouse actions in the client area and the second for mouse actions in the non-client area. Each group has an individual message for mouse down, mouse up and double-click actions. This allows you to detect XButton actions over individual windows or controls, however, there are few (if any) applications which offer the ability to perform a different action for these buttons on a per-control basis. Typically you want to use the buttons a similar way to Explorer or IE, which respond to clicks over any area of the window. This sample provides a class you can use to do either type of processing. The Subclassing and Timer assistant is used for detecting messages sent to an individual form or control, whilst the Hooking Library is used to detect events anywhere over a particular form. Detecting XButton Events Using a SubclassIn order to do this, you need to intercept all of the XButton mouse events sent or posted to the window you want to detect events for:
Decoding this information is performed using this code: Private Function ISubclass_WindowProc( _ ByVal hwnd As Long, _ ByVal iMsg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long ' Dim tP As POINTAPI Dim x As Single Dim y As Single Dim eShift As ShiftConstants Dim eBtn As XMouseButtonConstants Dim bConsumed As Boolean Select Case iMsg Case WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK tP.x = (lParam And &HFFFF) tP.y = (lParam And &H7FFF0000) \ &H10000 If (lParam And &H80000000) Then tP.y = tP.y Or &H8000& End If x = m_objTo.ScaleX(tP.x, vbTwips) y = m_objTo.ScaleX(tP.y, vbTwips) eBtn = (wParam And &H60&) eShift = (wParam And &HC&) If (iMsg = WM_XBUTTONDOWN) Then RaiseEvent XMouseDown(eBtn, eShift, x, y, bConsumed) ElseIf (iMsg = WM_XBUTTONUP) Then RaiseEvent XMouseUp(eBtn, eShift, x, y, bConsumed) Else RaiseEvent XBtnDblClick(eBtn, eShift, x, y, bConsumed) End If If (bConsumed) Then ISubclass_WindowProc = True End If Case WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, WM_NCXBUTTONDBLCLK GetCursorPos tP ScreenToClient m_hWnd, tP x = m_objTo.ScaleX(tP.x, vbTwips) y = m_objTo.ScaleX(tP.y, vbTwips) If (wParam And &H10000) = &H10000 Then eBtn = XBUTTON1 Else eBtn = XBUTTON2 End If eShift = _ vbShiftMask * Abs(Not (GetAsyncKeyState(vbKeyShift) = 0)) Or _ vbCtrlMask * Abs(Not (GetAsyncKeyState(vbKeyControl) = 0)) Or _ vbAltMask * Abs(Not (GetAsyncKeyState(vbKeyMenu) = 0)) If (iMsg = WM_XBUTTONDOWN) Then RaiseEvent XMouseDown(eBtn, eShift, x, y, bConsumed) ElseIf (iMsg = WM_XBUTTONUP) Then RaiseEvent XMouseUp(eBtn, eShift, x, y, bConsumed) Else RaiseEvent XBtnDblClick(eBtn, eShift, x, y, bConsumed) End If If (bConsumed) Then ISubclass_WindowProc = True End If End Select ' End Function Detecting XButton Events Using a HookA WH_MOUSE hook enables an application to be notified of all mouse actions prior to their occurrence. The information about the mouse action is provided in a MOUSEHOOKSTRUCT. This provided the screen position of the mouse, the handle to the window that would receive the event and the HitTest code for the mouse position. Unfortunately, this structure was defined before the XButtons were invented, and consequently does not provide any information about which of the two buttons were pressed. This can be worked around by using the GetAsyncKeyState function to check if the virtual key corresponding to the mouse button is pressed during mouse down events, and storing this information for use in the subsequent mouse up event. The code to parse the mouse information for the hook case is then: Private Function IWindowsHook_HookProc( _ ByVal eType As vbalWinHook.EHTHookTypeConstants, _ ByVal nCode As Long, _ ByVal wParam As Long, ByVal lParam As Long, _ bConsume As Boolean) As Long Dim tP As POINTAPI Dim tR As RECT Dim x As Single Dim y As Single Dim eShift As ShiftConstants Dim hWndA As Long Dim bOver As Boolean If ((wParam = WM_XBUTTONDOWN) Or _ (wParam = WM_XBUTTONUP) Or _ (wParam = WM_XBUTTONDBLCLK) Or _ (wParam = WM_NCXBUTTONDOWN) Or _ (wParam = WM_NCXBUTTONUP) Or _ (wParam = WM_NCXBUTTONDBLCLK)) Then If Not (GetAsyncKeyState(VK_XBUTTON1) = 0) Then m_eHookButtonDown = XBUTTON1 ElseIf Not (GetAsyncKeyState(VK_XBUTTON2) = 0) Then m_eHookButtonDown = XBUTTON2 End If GetCursorPos tP hWndA = WindowFromPoint(tP.x, tP.y) Do While Not (bOver) And Not (hWndA = 0) If (hWndA = m_hWnd) Then bOver = True Else hWndA = GetParent(hWndA) End If Loop If bOver Then ScreenToClient m_hWnd, tP x = m_objTo.ScaleX(tP.x, vbTwips) y = m_objTo.ScaleX(tP.y, vbTwips) eShift = _ vbShiftMask * Abs(Not (GetAsyncKeyState(vbKeyShift) = 0)) Or _ vbCtrlMask * Abs(Not (GetAsyncKeyState(vbKeyControl) = 0)) Or _ vbAltMask * Abs(Not (GetAsyncKeyState(vbKeyMenu) = 0)) bConsume = True If (wParam = WM_XBUTTONDOWN) Or (wParam = WM_NCXBUTTONDOWN) Then RaiseEvent XMouseDown(m_eHookButtonDown, eShift, x, y, bConsume) ElseIf (wParam = WM_XBUTTONUP) Or (wParam = WM_NCXBUTTONUP) Then RaiseEvent XMouseUp(m_eHookButtonDown, eShift, x, y, bConsume) Else RaiseEvent XBtnDblClick(m_eHookButtonDown, eShift, x, y, bConsume) End If End If End If End Function Wrap-UpUsing a Windows Hook you can provide X Mouse Button functionality to match Explorer and IE from your VB app.
|
|
|