|
|
获取鼠标光标在屏幕上的位置和移动鼠标光标,分别需调用API函数GetCursorPos和SetCursorPos。这两个函数的接口声明如下:
Declare Function GetCursorPos Lib “user32" (lpPoint As POINTAPI) As Long
Declare Function SetCursorPos Lib “user32" (ByVal X As Long, ByVal Y As Long) As Long
在SetCursorPos函数中,参数X和Y指定了鼠标光标在屏幕上的坐标。GetCursorPos函数把鼠标光标的当前位置存到结构变量lpPoint中。结构变量的定义如下:
Private Type POINTAPI
X As Long
Y As Long
End Type
按钮的Left和Top属性给出的是按钮的左上角在窗口客户区坐标系中的坐标位置。要把鼠标光标移到按钮正中,需要得到按钮中心在屏幕坐标系中的坐标位置。窗口客户区坐标系与屏幕坐标系不仅坐标原点不同,二者的坐标单位(scale)也不同。窗口客户区坐标系的单位是Twip,屏幕坐标系单位是Pixel,二者的关系可以从屏幕对象Screen的TwipsPerPixelX和TwipsPerPixelY属性获取。这两个属性分别代表了水平和垂直两个方向上的单位转换比例。
把按钮中心在窗口客户区中的坐标单位转换为屏幕坐标系的单位后,还要通过一个API函数进行坐标平移变换,最终取得按钮中心在屏幕坐标系中的坐标位置。这个API函数的接口声明如下:
Declare Function ClientToScreen Lib “user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
最后一步是自动按下和放开按钮,这是通过模拟鼠标左键的按下和放开来实现的。该功能需调用API函数SendMessage向按钮发一对鼠标左键按下和放开的消息,函数接口声明如下:
Declare Function SendMessage Lib “user32" Alias “SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
SendMessage函数的hwnd参数为接收消息的窗口或控件的hwnd句柄。wMsg参数指定具体的消息值。在本例中,要发送鼠标左键按下和释放的消息,wMsg的取值分别为WM_LBUTTONDOWN和WM_LBUTTONUP,这两个常量定义如下:
Const WM_LBUTTONDOWN = &H201
Const WM_LBUTTONUP = &H202
把这两个消息发送给一个按钮,按钮就会像真的被鼠标左键单击了一样。SendMessage函数中的后两个参数在本例中可以不理,简单置0即可。
还有一点细节需注意。如果连续给按钮发送一对WM_LBUTTONDOWN和WM_LBUTTONUP消息,Windows会来不及进行一些必要的系统操作,这样在视觉上就看不出按钮被按下后又放开的效果,好像按钮没有按动。但按钮的Click事件处理过程被激活执行表明按钮确实被按过。为了达到视觉上的完美效果,我们不妨在WM_LBUTTONDOWN和WM_LBUTTONUP两个消息之间插入一段短短的延时,比如说200毫秒,在这段延时期间,把处理权交给Windows,这样Windows就有时间显示按钮被按下的效果了。插入延时的办法有很多,可以加入一段空循环或利用计时器控件,这里再介绍一个API函数GetTickCount,该函数获取自Windows启动至被调用时所经过的毫秒数。利用这个函数控制延时,不仅精确,而且节省资源。 GetTickCount 函数的接口声明如下:
Declare Function GetTickCount Lib “kernel32" () As Long
下面进行窗体设计。我们在窗体Form1中安插一个按钮Command1。Command1的Click事件处理过程调用VB的Beep产生一声蜂鸣。另外在Form1的主菜单上加上一个ClickButton的菜单命令,热键设为Alt-C,该菜单命令的事件处理过程完成对鼠标光标的遥控。
最后给出Form1的完整程序清单:
Begin VB.Form Form1
BorderStyle = 1 'Fixed Single
Caption = “Auto-click demonstration"
ClientHeight = 3195
ClientLeft = 150
ClientTop = 720
ClientWidth = 4680
LinkTopic = “Form1"
MaxButton = 0 'False
ScaleHeight = 3195
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
Begin VB.CommandButton Command1
Caption = “Click me!"
Height = 495
Left = 1740
TabIndex = 0
Top = 1380
Width = 1215
End
Begin VB.Menu mnuClickButton
Caption = “&ClickButton"
End
End
Attribute VB_Name = “Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Private Type POINTAPI
X As Long
Y As Long
End Type
Const WM_LBUTTONDOWN = &H201
Const WM_LBUTTONUP = &H202
Dim ButtonPos As POINTAPI
Private Declare Function GetCursorPos Lib “ user32" (lpPoint As POINTAPI) As LongPrivate Declare Function SetCursorPos Lib “user32" (ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function SendMessage Lib “ user32" Alias “SendMessageA" (ByValhwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPrivate Declare Function ClientToScreen Lib “user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
Private Declare Function GetTickCount Lib “ kernel32" () As Long
Private Sub Command1_Click()
Beep
End Sub
Private Sub Form_Load()
Dim tmp As Long
With Command1
ButtonPos.X = (.Left + .Width / 2) / Screen.TwipsPerPixelX
ButtonPos.Y = (.Top + .Height / 2) / Screen.TwipsPerPixelY
End With
tmp = ClientToScreen(Me.hwnd, ButtonPos)
End Sub
Private Sub mnuClickButton_Click()
Const MoveStep As Integer = 50
Dim CursorPos As POINTAPI
Dim DistX As Double, DistY As Double
Dim tmp As Long
Dim i As Integer
Dim PosX As Integer, PosY As Integer
Dim TickCount As Long
tmp = GetCursorPos(CursorPos)
DistX = ButtonPos.X - CursorPos.X
DistY = ButtonPos.Y - CursorPos.Y
For i = 1 To MoveStep
PosX = CursorPos.X+DistX*i / MoveStep
PosY = CursorPos.Y+DistY*i / MoveStep
tmp = SetCursorPos(PosX, PosY)
Next i
tmp = SendMessage(Command1.hwnd,
WM_LBUTTONDOWN, 0, 0)
TickCount = GetTickCount()
While GetTickCount() - TickCount < 200
tmp = DoEvents()
Wend
tmp = SendMessage(Command1.hwnd,
WM_LBUTTONUP, 0, 0)
End Sub |
|