2016-11-29 87 views
0

這不是一個問題,更多的解決方案。我一直在試圖編寫一個例程,它允許我按下我的遊戲杆(發送DX按鈕)上的一個鍵並模擬同時按下並保持一個鍵在向下的位置。基本上,它歸結爲三行代碼:按一個鍵,然後釋放它

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 

爲了清楚起見,添加了行號。如您所見,第20行按住SCROLL LOCK鍵,第30行再次釋放。儘管代碼完全符合我的需求(在1小時35分鐘的會話中,我在Falcon BMS 4.33U2,IVC Client和FRAPS中沒有遇到任何問題),但爲了使其發揮作用,我必須使用調試>例外>託管調試助手> PInvokeStackImbalance(拋出)。

我的問題是 - 這是一個「安全」的方式來編程,或者換句話說,我欺騙了某個地方讓這個工作?如果它不「安全」,是否有適當的方法來做同樣的事情?

+0

'keybd_event'已被棄用,所以是'聲明。 ..Lib'。當前發送鍵盤/鼠標事件的方法是使用[**'SendInput()'**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v = vs。 85)的.aspx)。看到我的鍵盤輸入包裝[**在這個答案**](http://stackoverflow.com/questions/39809095/why-do-some-applications-not-accept-some-sendkeys-at-some-times/39811061 #39811061)。 –

+0

看看這個例子: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx 這是爲numloc,但根據您應該使用KEYEVENTF_EXTENDEDKEY的信息。 第二:COndition的背後是什麼?是這樣的: GetKeyboardState((LPBYTE)&keyState);例如。獲取當前的關鍵狀態? 第三,您可以嘗試使用SetInput而不是keybg_event,因爲keybg_event被取代 – Kiko

+0

如果函數被正確聲明,則根本沒有錯誤。 「Thrown」複選框在默認情況下不應該勾選任何異常,因爲即使處理異常,它也會中斷應用程序。 –

回答

0

正如我在我的評論中所說keybd_event()已棄用,由SendInput()替代。但是,您收到PInvokeStackImbalance異常的原因是因爲函數聲明中最後兩個參數是錯誤的。

幾乎所有Declare...Lib的例子都是針對VB 6或更低版本設計的,例如Long與VB.NET的Long數據類型不一樣。我建議你到總是尋找P/Invoke片段使用DllImport attribute。如果找不到VB.NET版本,則可以查找C#代碼片段,然後使用在線轉換器轉換它們。

要修復錯誤,最後兩個參數應該是UIntegerUIntPtr

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

然而,正如我說的,建議堅持DllImport

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

您可以檢查pinvoke.net對於P/Invoke的片段。


要使用今天推薦的方法SendInput(),你可以利用我的InputHelper類:

Imports System.Runtime.InteropServices 

Public NotInheritable Class InputHelper 
    Private Sub New() 
    End Sub 

#Region "Methods" 
#Region "PressKey()" 
    ''' <summary> 
    ''' Virtually presses a key. 
    ''' </summary> 
    ''' <param name="Key">The key to press.</param> 
    ''' <param name="HardwareKey">Whether or not to press the key using its hardware scan code.</param> 
    ''' <remarks></remarks> 
    Public Shared Sub PressKey(ByVal Key As Keys, Optional ByVal HardwareKey As Boolean = False) 
     If HardwareKey = False Then 
      InputHelper.SetKeyState(Key, False) 
      InputHelper.SetKeyState(Key, True) 
     Else 
      InputHelper.SetHardwareKeyState(Key, False) 
      InputHelper.SetHardwareKeyState(Key, True) 
     End If 
    End Sub 
#End Region 

#Region "SetKeyState()" 
    ''' <summary> 
    ''' Virtually sends a key event. 
    ''' </summary> 
    ''' <param name="Key">The key of the event to send.</param> 
    ''' <param name="KeyUp">Whether to push down or release the key.</param> 
    ''' <remarks></remarks> 
    Public Shared Sub SetKeyState(ByVal Key As Keys, ByVal KeyUp As Boolean) 
     Key = ReplaceBadKeys(Key) 

     Dim KeyboardInput As New KEYBDINPUT With { 
      .wVk = Key, 
      .wScan = 0, 
      .time = 0, 
      .dwFlags = If(KeyUp, KEYEVENTF.KEYUP, 0), 
      .dwExtraInfo = IntPtr.Zero 
     } 

     Dim Union As New INPUTUNION With {.ki = KeyboardInput} 
     Dim Input As New INPUT With { 
      .type = INPUTTYPE.KEYBOARD, 
      .U = Union 
     } 

     SendInput(1, New INPUT() {Input}, Marshal.SizeOf(GetType(INPUT))) 
    End Sub 
#End Region 

#Region "SetHardwareKeyState()" 
    ''' <summary> 
    ''' Virtually sends a key event using the key's scan code. 
    ''' </summary> 
    ''' <param name="Key">The key of the event to send.</param> 
    ''' <param name="KeyUp">Whether to push down or release the key.</param> 
    ''' <remarks></remarks> 
    Public Shared Sub SetHardwareKeyState(ByVal Key As Keys, ByVal KeyUp As Boolean) 
     Key = ReplaceBadKeys(Key) 

     Dim KeyboardInput As New KEYBDINPUT With { 
      .wVk = 0, 
      .wScan = MapVirtualKeyEx(CUInt(Key), 0, GetKeyboardLayout(0)), 
      .time = 0, 
      .dwFlags = KEYEVENTF.SCANCODE Or If(KeyUp, KEYEVENTF.KEYUP, 0), 
      .dwExtraInfo = IntPtr.Zero 
     } 

     Dim Union As New INPUTUNION With {.ki = KeyboardInput} 
     Dim Input As New INPUT With { 
      .type = INPUTTYPE.KEYBOARD, 
      .U = Union 
     } 

     SendInput(1, New INPUT() {Input}, Marshal.SizeOf(GetType(INPUT))) 
    End Sub 
#End Region 

#Region "ReplaceBadKeys()" 
    ''' <summary> 
    ''' Replaces bad keys with their corresponding VK_* value. 
    ''' </summary> 
    ''' <remarks></remarks> 
    Private Shared Function ReplaceBadKeys(ByVal Key As Keys) As Keys 
     Dim ReturnValue As Keys = Key 

     If ReturnValue.HasFlag(Keys.Control) Then 
      ReturnValue = (ReturnValue And Not Keys.Control) Or Keys.ControlKey 'Replace Keys.Control with Keys.ControlKey. 
     End If 

     If ReturnValue.HasFlag(Keys.Shift) Then 
      ReturnValue = (ReturnValue And Not Keys.Shift) Or Keys.ShiftKey 'Replace Keys.Shift with Keys.ShiftKey. 
     End If 

     If ReturnValue.HasFlag(Keys.Alt) Then 
      ReturnValue = (ReturnValue And Not Keys.Alt) Or Keys.Menu 'Replace Keys.Alt with Keys.Menu. 
     End If 

     Return ReturnValue 
    End Function 
#End Region 
#End Region 

#Region "WinAPI P/Invokes" 
    <DllImport("user32.dll", SetLastError:=True)> 
    Private Shared Function SendInput(ByVal nInputs As UInteger, <MarshalAs(UnmanagedType.LPArray)> ByVal pInputs() As INPUT, ByVal cbSize As Integer) As UInteger 
    End Function 

    <DllImport("user32.dll")> _ 
    Private Shared Function MapVirtualKeyEx(uCode As UInteger, uMapType As UInteger, dwhkl As IntPtr) As UInteger 
    End Function 

    <DllImport("user32.dll")> _ 
    Private Shared Function GetKeyboardLayout(idThread As UInteger) As IntPtr 
    End Function 

#Region "Enumerations" 
    Private Enum INPUTTYPE As UInteger 
     MOUSE = 0 
     KEYBOARD = 1 
     HARDWARE = 2 
    End Enum 

    <Flags()> _ 
    Private Enum KEYEVENTF As UInteger 
     EXTENDEDKEY = &H1 
     KEYUP = &H2 
     SCANCODE = &H8 
     UNICODE = &H4 
    End Enum 
#End Region 

#Region "Structures" 
    <StructLayout(LayoutKind.Explicit)> _ 
    Private Structure INPUTUNION 
     <FieldOffset(0)> Public mi As MOUSEINPUT 
     <FieldOffset(0)> Public ki As KEYBDINPUT 
     <FieldOffset(0)> Public hi As HARDWAREINPUT 
    End Structure 

    Private Structure INPUT 
     Public type As Integer 
     Public U As INPUTUNION 
    End Structure 

    Private Structure MOUSEINPUT 
     Public dx As Integer 
     Public dy As Integer 
     Public mouseData As Integer 
     Public dwFlags As Integer 
     Public time As Integer 
     Public dwExtraInfo As IntPtr 
    End Structure 

    Private Structure KEYBDINPUT 
     Public wVk As UShort 
     Public wScan As Short 
     Public dwFlags As UInteger 
     Public time As Integer 
     Public dwExtraInfo As IntPtr 
    End Structure 

    Private Structure HARDWAREINPUT 
     Public uMsg As Integer 
     Public wParamL As Short 
     Public wParamH As Short 
    End Structure 
#End Region 
#End Region 
End Class 

例如:

If condition = True Then 
    InputHelper.SetKeyState(Keys.Scroll, False) 'Key down. 
Else 
    InputHelper.SetKeyState(Keys.Scroll, True) 'Key up. 
End If 
相關問題