我试图在按下它时自动重复LButton,然后在它被释放时停止,我遇到了一个问题,即使它没有按下它也会不断重复.
这有什么变通方法吗?我需要它也可以用于其他应用程序,这就是我使用GetAsyncKeyState的原因.
这是我到目前为止:
- Imports System.Threading
- Public Class Form1
- Const KeyDownBit As Integer = &H8000
- Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vkey As Integer) As Short
- Private Declare Sub mouse_event Lib "user32" (ByVal dwflags As Integer,ByVal dx As Integer,ByVal cbuttons As Integer,ByVal dy As Integer,ByVal dwExtraInfo As Integer)
- Private Const mouseclickup = 4
- Private Const mouseclickdown = 2
- Private Sub Timer1_Tick(sender As Object,e As EventArgs) Handles Timer1.Tick
- If (GetAsyncKeyState(Keys.LButton) And KeyDownBit) = KeyDownBit Then
- mouse_event(mouseclickup,0)
- Thread.Sleep(100)
- mouse_event(mouseclickdown,0)
- End If
- End Sub
使用此代码,当我左键单击时,即使释放Lbutton,代码也会不断自动点击,但这并不是我想要的.我想要它,所以当我按住LButton时,它会不断点击,然后当LButton被释放时,它会停止点击.
我尝试过使用BackgroundWorker,尽管发生了同样的事情.
我也试过在mouse_event(mouseclickup,0)之前使用mouse_event(mouseclickdown,0),但是每次按下它时它只需单击一次就会双击,然后停止.
LMB持续点击的原因是每次检测到LMB时都会发送新的鼠标.
由于GetAsyncKeyState()读取键盘/鼠标输入流,因此您无法使用任何向流添加点击的方法,因为一切都会像您当前遇到的那样陷入困境.
为了消除这个问题,我将一个帮助类放在一起,该方法将鼠标点击作为窗口消息发送到点击点下方的窗口.通过这样做,我们现在直接将鼠标点击发送到窗口而不是键盘/鼠标输入流,这意味着GetAsyncKeyState()将不会注意到它.
MouseInputHelper.vb
- Imports System.Runtime.InteropServices
- Public NotInheritable Class MouseInputHelper
- Private Sub New()
- End Sub
- #Region "Methods"
- #Region "SendMouseClick()"
- ''' <summary>
- ''' Sends a Window Message-based mouse click to the specified coordinates of the screen.
- ''' </summary>
- ''' <param name="Button">The button to press.</param>
- ''' <param name="Location">The position where to send the click (in screen coordinates).</param>
- ''' <remarks></remarks>
- Public Shared Sub SendMouseClick(ByVal Button As MouseButtons,ByVal Location As Point)
- Dim hWnd As IntPtr = NativeMethods.WindowFromPoint(New NativeMethods.NATIVEPOINT(Location.X,Location.Y)) 'Get the window at the specified click point.
- Dim ButtonMessage As NativeMethods.MouseButtonMessages = NativeMethods.MouseButtonMessages.None 'A variable holding which Window Message to use.
- Select Case Button 'Set the appropriate mouse button Window Message.
- Case MouseButtons.Left : ButtonMessage = NativeMethods.MouseButtonMessages.WM_LBUTTONDOWN
- Case MouseButtons.Right : ButtonMessage = NativeMethods.MouseButtonMessages.WM_RBUTTONDOWN
- Case MouseButtons.Middle : ButtonMessage = NativeMethods.MouseButtonMessages.WM_MBUTTONDOWN
- Case MouseButtons.XButton1,MouseButtons.XButton2
- ButtonMessage = NativeMethods.MouseButtonMessages.WM_XBUTTONDOWN
- Case Else
- Throw New InvalidOperationException("Invalid mouse button " & Button.ToString())
- End Select
- Dim ClickPoint As New NativeMethods.NATIVEPOINT(Location.X,Location.Y) 'Create a native point.
- If NativeMethods.ScreenToClient(hWnd,ClickPoint) = False Then 'Convert the click point to client coordinates relative to the window.
- Throw New Exception("Unable to convert screen coordinates to client coordinates! Win32Err: " & _
- Marshal.GetLastWin32Error())
- End If
- Dim wParam As IntPtr = IntPtr.Zero 'Used to specify which X button was clicked (if any).
- Dim lParam As IntPtr = NativeMethods.CreateLWParam(ClickPoint.X,ClickPoint.Y) 'Click point.
- If Button = MouseButtons.XButton1 OrElse _
- Button = MouseButtons.XButton2 Then
- wParam = NativeMethods.CreateLWParam(0,Button / MouseButtons.XButton1) 'Set the correct XButton.
- End If
- NativeMethods.SendMessage(hWnd,ButtonMessage,wParam,lParam) 'Button down.
- NativeMethods.SendMessage(hWnd,ButtonMessage + 1,lParam) 'Button up.
- End Sub
- #End Region
- #End Region
- #Region "NativeMethods"
- Private NotInheritable Class NativeMethods
- Private Sub New()
- End Sub
- <DllImport("user32.dll",SetLastError:=True,CharSet:=CharSet.Auto)> _
- Public Shared Function SendMessage(ByVal hWnd As IntPtr,ByVal Msg As UInteger,ByVal wParam As IntPtr,ByVal lParam As IntPtr) As IntPtr
- End Function
- <DllImport("user32.dll",SetLastError:=True)> _
- Public Shared Function WindowFromPoint(ByVal p As NATIVEPOINT) As IntPtr
- End Function
- <DllImport("user32.dll",SetLastError:=True)> _
- Public Shared Function ScreenToClient(ByVal hWnd As IntPtr,ByRef lpPoint As NATIVEPOINT) As Boolean
- End Function
- <StructLayout(Runtime.InteropServices.LayoutKind.Sequential)> _
- Public Structure NATIVEPOINT
- Public X As Integer
- Public Y As Integer
- Public Sub New(ByVal X As Integer,ByVal Y As Integer)
- Me.X = X
- Me.Y = Y
- End Sub
- End Structure
- Public Shared Function CreateLWParam(LoWord As Integer,HiWord As Integer) As IntPtr
- Return New IntPtr((HiWord << 16) Or (LoWord And &HFFFF))
- End Function
- #Region "Enumerations"
- Public Enum MouseButtonMessages As Integer
- None = 0
- WM_LBUTTONDOWN = &H201
- WM_LBUTTONUP = &H202
- WM_MBUTTONDOWN = &H207
- WM_MBUTTONUP = &H208
- WM_RBUTTONDOWN = &H204
- WM_RBUTTONUP = &H205
- WM_XBUTTONDOWN = &H20B
- WM_XBUTTONUP = &H20C
- XBUTTON1 = &H1
- XBUTTON2 = &H2
- End Enum
- #End Region
- End Class
- #End Region
- End Class
现在在您的计时器中,您可以:
- Const KeyDownBit As Integer = &H8000
- Private Sub Timer1_Tick(sender As Object,e As EventArgs) Handles Timer1.Tick
- If (GetAsyncKeyState(Keys.LButton) And KeyDownBit) = KeyDownBit Then
- MouseInputHelper.SendMouseClick(Windows.Forms.MouseButtons.Left,Cursor.Position)
- End If
- End Sub
希望这可以帮助!