DOCUMENT:Q186428 01-JUN-1998 [vbwin] TITLE :HOWTO: Implement the 'SnapTo' Feature in Visual Basic PRODUCT :Microsoft Visual Basic for Windows PROD/VER:WINDOWS:5.0 OPER/SYS:WINDOWS KEYWORDS:kbVBp500 ====================================================================== --------------------------------------------------------------------- The information in this article applies to: - Microsoft Visual Basic Learning, Professional, and Enterprise Editions for Windows, version 5.0 --------------------------------------------------------------------- SUMMARY ======= The 'SnapTo' feature of Microsoft IntelliPoint Software version 2.0, which automatically places the mouse pointer over the default button of a form, does not work with Visual Basic forms. This article presents a way to achieve this functionality in Visual Basic. MORE INFORMATION ================ This article uses a class module to make the necessary Windows API calls. One possible extension to this article would be to compile the class code into an ActiveX DLL, and that is why a class module was used. This is a good approach if the 'Snap To' functionality is needed in a number of different projects. The mouse cursor will not be adjusted unless the 'Snap To' functionality is enabled on the target machine. NOTE: Under Windows 95 and Windows 98, the 'Snap To' functionality does not interact properly with Visual Basic 5.0 applications under some circumstances. Please see the REFERENCES section of this article for more information on this topic. Step-by-Step Example -------------------- 1. Start a new Standard EXE project in Visual Basic. Form1 is created by default. Add a second Form to the Project. 2. Place two CommandButtons on Form1. Set the Default property of Command2 to True. 3. Add a Class Module to the Project. Change the property name of the Class Module to Snap. 4. Add the following code to the Snap Class module: Option Explicit Private Declare Function SetCursorPos Lib "user32" _ (ByVal x As Long, ByVal y As Long) As Long Private Declare Function GetWindowRect Lib "user32" _ (ByVal hwnd As Long, lpRect As RECT) As Long Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias _ "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _ ByVal ulOptions As Long, ByVal samDesired As Long, phkResult _ As Long) As Long Private Declare Function RegQueryValueEx Lib "advapi32.dll" Alias _ "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName _ As String, ByVal lpReserved As Long, lpType As Long, lpData As Any, _ lpcbData As Long) As Long Private Declare Function RegCloseKey Lib "advapi32.dll" _ (ByVal hKey As Long) As Long Private Type RECT left As Long top As Long right As Long bottom As Long End Type Private Const HKEY_C_U = &H80000001 ' HKEY_CURRENT_USER Private Const subkey = "Control Panel\Microsoft Input Devices\Mouse" Private buttonHandle As Long Public Sub setDefaultButton(colControls As Object) Dim iIterate As Integer For iIterate = 0 To colControls.Count - 1 If TypeOf colControls(iIterate) Is CommandButton Then If colControls(iIterate).Default = True Then buttonHandle = colControls(iIterate).hwnd Exit For End If End If Next iIterate End Sub Public Function snapTo() Dim buttonRect As RECT Dim RetVal As Long Dim x As Long Dim y As Long If buttonHandle And _ RegGetString$(HKEY_C_U, subkey, "SnapTo") = "ON" Then RetVal = GetWindowRect(buttonHandle, buttonRect) With buttonRect x = .left + ((.right - .left) / 2) y = .top + ((.bottom - .top) / 2) End With DoEvents RetVal = SetCursorPos(x, y) snapTo = True Else snapTo = False End If End Function Function RegGetString$(hInKey As Long, ByVal subkey$, ByVal valname$) Dim RetVal$, hSubKey As Long, dwType As Long, vSZ As Long Dim R As Long, v$ RetVal$ = "" Const ERROR_SUCCESS& = 0 Const REG_SZ& = 1 Const KEY_READ = &H20019 R = RegOpenKeyEx(hInKey, subkey$, 0, KEY_READ, hSubKey) If R <> ERROR_SUCCESS Then GoTo Quit_Now vSZ = 256: v$ = String$(vSZ, 0) R = RegQueryValueEx(hSubKey, valname$, 0, dwType, ByVal v$, vSZ) If R = ERROR_SUCCESS And dwType = REG_SZ Then RetVal$ = left$(v$, vSZ - 1) Else RetVal$ = "--Not String--" End If If hInKey = 0 Then R = RegCloseKey(hSubKey) Quit_Now: RegGetString$ = RetVal$ End Function 5. Insert the following into the General Declarations section of Form1: Dim objSnap As Snap Private Sub Command1_Click() Form2.Show End Sub Private Sub Form_Activate() objSnap.snapTo End Sub Private Sub Form_Load() Command1.Caption = "Show Form2" Command2.Caption = "Default Button" Set objSnap = New Snap ' determine the default button and save it in the Snap class Call objSnap.setDefaultButton(Me.Controls) End Sub Private Sub Form_Unload(Cancel As Integer) Set objSnap = Nothing End Sub 6. Run the project. When Form1 opens, the mouse pointer should be centered over the button with the caption "Default Button." 7. Click on Command2 to open the other form. 8. Click back and forth between Form1 or Form2, either by clicking on the forms themselves, or on the form Icons in the Windows TaskBar. When focus returns to Form1, the mouse pointer should be positioned on the default button. NOTE: This technique only works when shifting between forms of the same application. To make it work properly when your application gains focus would require hooking the WM_ACTIVATEAPP message, because Visual Basic does not have an App_Activate event. Please refer to the REFERENCES section of this article for more information on this topic. REFERENCES ========== For additional information, please see the following articles in the Microsoft Knowledge Base: ARTICLE-ID: Q143274 TITLE : HOWTO: Retrieve Printer Name from Windows 95 Registry in VB ARTICLE-ID: Q166199 TITLE : SnapTo Feature May Not Work in Mouse Orientation Tool ARTICLE-ID: Q168795 TITLE : HOWTO: Hook Into a Window's Messages Using AddressOf ARTICLE-ID: Q186430 TITLE : PRB: Intellipoint 'Snap To' Feature and VB5 Applications Additional query words: kbDSupport kbDSD kbMouse kbInterop kbVBp500 ====================================================================== Keywords : kbVBp500 Version : WINDOWS:5.0 Platform : WINDOWS Issue type : kbhowto ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 1998.