vb.net – 如何在按住键的同时以编程方式重复键?

我试图在按下它时自动重复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

希望这可以帮助!

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...