0

This is not a question as such, more a solution. I have been trying to code a routine which will allow me to press a key on my Joystick (which sends a DX button) and simulates pressing and holding a key in the down position at the same time. Basically, it boiled down to three lines of code:

    10. Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

    20. If (condition=true) then
    30.     keybd_event(Keys.Scroll, 0, 0, 0)
    40. Else
    50.     keybd_event(Keys.Scroll, 0, 2, 0)
    60. EndIf

Line numbers added for clarity. As you can see, line 20 holds down the SCROLL LOCK key, line 30 releases it again. Although the code works perfectly for my needs (in a 1 hour 35 minute session I experienced no problems in Falcon BMS 4.33U2, IVC Client, and FRAPS), to get this to work, I had to disable the MDA using Debug>Exceptions>Managed Debugging Assistants>PInvokeStackImbalance (thrown).

My question is - is this a "safe" way to program, or in other words, have I cheated somewhere to get this to work? If it is not "safe", is there a proper way to do the same thing?

  • `keybd_event` is deprecated, and so is `Declare...Lib`. The current way to send keyboard/mouse events is by using [**`SendInput()`**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx). See my keyboard input wrapper [**in this answer**](http://stackoverflow.com/questions/39809095/why-do-some-applications-not-accept-some-sendkeys-at-some-times/39811061#39811061). – Visual Vincent Nov 29 '16 at 19:44
  • Have a look at this example: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx It is for numloc, but according to the info you should use KEYEVENTF_EXTENDEDKEY. Second: what stands behind the COndition? Is it something like: GetKeyboardState((LPBYTE)&keyState); E.g. to get the current key state? Third you can try to use SetInput instead of keybg_event, since keybg_event is superseded – Kiko Nov 29 '16 at 19:45
  • If the function was declared correctly, there should be no errors at all. The `Thrown` check box shouldn't be ticked for any exception by default, since it will break the application even if the exception is handled. – Visual Vincent Nov 29 '16 at 19:47
  • That is a VB6 declaration. Long is not correct and trips the MDA. Very nasty, never ignore that. [Correct one is here](http://pinvoke.net/default.aspx/user32/keybd_event.html). – Hans Passant Nov 29 '16 at 19:55

1 Answers1

0

As I said in my comment keybd_event() is deprecated and replaced by SendInput(). However the reason you are receiving a PInvokeStackImbalance exception is because the last two parameters is wrong in your function declaration.

Almost all Declare...Lib examples out there are designed for VB 6 or lower, where for example Long isn't the same as VB.NET's Long data type. I advice you to always look for P/Invoke snippets using the DllImport attribute. If you can't find a VB.NET version, you can look for C# snippets instead and convert them using an online converter.

To fix the error the last two parameters should be of type UInteger and UIntPtr.

Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As UInteger, ByVal dwExtraInfo As UIntPtr)

However, as I said it is recommended to stick to DllImport:

<DllImport("user32.dll")> _
Public Shared Sub keybd_event(bVk As Byte, bScan As Byte, dwFlags As UInteger, dwExtraInfo As UIntPtr)
End Function

You can check pinvoke.net for P/Invoke snippets.


To use the today recommended method SendInput(), you can utilize my InputHelper class:

EDIT (2019-09-20)

InputHelper has since long been moved to its own library. The answer has been updated to reflect this change.

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

For example:

If condition = True Then
    InputHelper.SetKeyState(Keys.Scroll, True) 'Key down.
Else
    InputHelper.SetKeyState(Keys.Scroll, False) 'Key up.
End If
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75