Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

vb.net - How do I programmatically repeat a key while it is held?

I'm trying to automatically repeat LButton while it's held down, then stop when it's released, I've ran into a problem where it will continuously repeat itself even while it's not been held down.

Is there any workarounds for this? I need it to also work on other applications which is why I'm using GetAsyncKeyState.

This is what I have so far:

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, 0, 0, 0)
            Thread.Sleep(100)
            mouse_event(mouseclickdown, 0, 0, 0, 0)
        End If
  End Sub

With this code, when I left click, the code will continuously keep clicking automatically even when Lbutton is released, but that's not exactly what i want. I want it so when I hold LButton, it will then continuously click, then when LButton is released, it will stop clicking.

I have tried using a BackgroundWorker, although the same thing happens.

I have also tried having mouse_event(mouseclickdown, 0, 0, 0, 0) before mouse_event(mouseclickup, 0, 0, 0, 0), but then it just turns a single click into a double click each time it's pressed down, then stops.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The reason LMB keeps getting clicked is because you keep sending a new mouse click every time you detect one.

Since GetAsyncKeyState() reads the keyboard/mouse input stream you cannot use any method that adds clicks to the stream since everything will get stuck like you are currently experiencing.

In order to eliminate the problem I put together a helper class with a method that will send mouse clicks as window messages to the window below the click point. By doing so we are now sending mouse clicks directly to the window instead of the keyboard/mouse input stream, meaning that GetAsyncKeyState() won't take notice of it.

EDIT (2019-08-16)

The MouseInputHelper class has since long been merged with InputHelper. The answer has been updated to use the latter instead.

Download InputHelper from GitHub:
https://github.com/Visual-Vincent/InputHelper/releases

Now in your timer you can do:

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    If InputHelper.Mouse.IsButtonDown(MouseButtons.Left) Then
        InputHelper.WindowMessages.SendMouseClick(MouseButtons.Left, Cursor.Position)
    End If
End Sub

Hope this helps!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...