如何在VBA中使用SendInput函数组合按键以控制Chrome窗口?

huangapple go评论161阅读模式
英文:

How can I use SendInput function in VBA to combine keystrokes for Chrome window?

问题

Here's the translation of the code you provided:

  1. 我想在VBA中使用Windows APISendinput函数,将一组按键发送到窗口,例如Ctrl H发送到Chrome。我选择sendinput(),因为sendmessage不允许同时发送一组键,窗口会分别接收它们。另一方面,VBA中的SendKeys方法据说不可靠。
  2. 因此,在阅读文档并进行谷歌搜索后,我得到了这段代码:
  3. ' 以下为代码部分,不翻译
  4. ' ...
  5. 所以当我运行代码时,它轻松找到了Chrome窗口。但是当运行Ctrl_H()子过程时,似乎无法运行,尽管我付出了大量工作。我在互联网上找到的所有代码,包括在Stack Exchange上的(https://stackoverflow.com/questions/13896658/sendinput-vb-basic-example),都无法正常工作。如果有人有任何解决方案,我将非常感激。

Please note that I've excluded the code part from translation, as requested. If you have any specific questions or need assistance with this code, feel free to ask.

英文:

I want to use Sendinput function of Windows API in VBA to send a combination of keystrokes to a window, for example Ctrl H to Chrome. I choose sendinput() because sendmessage would not allow me to send a combination of key at the same time, the window will receive them seperately. On the other hand, the SendKeys method in VBA is said to be unreliable.

So after read the documentation and google search, I reach to this code

  1. Option Explicit
  2. Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
  3. (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
  4. Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
  5. (ByVal hWnd As LongPtr, ByVal hWndChild As LongPtr, _
  6. ByVal lpszClass As String, ByVal lpszWindow As String) As LongPtr
  7. Private Declare PtrSafe Function ShowWindow Lib "user32" _
  8. (ByVal hWnd As LongPtr, ByVal nCmdShow As Long) As Boolean
  9. Private Declare PtrSafe Function SetForegroundWindow Lib "user32" _
  10. (ByVal hWnd As LongPtr) As Boolean
  11. Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
  12. (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
  13. Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" _
  14. (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
  15. Private Declare PtrSafe Function GetWindow Lib "user32" _
  16. (ByVal hWnd As LongPtr, ByVal wCmd As Long) As LongPtr
  17. Private Declare PtrSafe Function EnumChildWindows Lib "user32" _
  18. (ByVal hWnd As LongPtr, ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
  19. Private Declare PtrSafe Function GetWindowText Lib "user32" Alias _
  20. "GetWindowTextA" (ByVal hWnd As LongPtr, ByVal lpWindowText As String, ByVal nMaxCount As LongPtr) As Long
  21. Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
  22. Private Declare PtrSafe Function GetWindowTextLength Lib "user32" Alias _
  23. "GetWindowTextLengthA" (ByVal hWnd As LongPtr) As Long
  24. Public Declare PtrSafe Sub Sleep Lib "kernel32" _
  25. (ByVal dwMilliseconds As LongPtr)
  26. Private Declare PtrSafe Function SendInput Lib "user32" ( _
  27. ByVal nInputs As LongPtr, _
  28. ByRef pInputs As Any, _
  29. ByVal cbSize As LongPtr) As Long
  30. Private Const SW_SHOWNORMAL As Long = 1
  31. Private Const WM_SETTEXT As Long = &HC
  32. Private Const VK_RETURN As Integer = &HD
  33. Private Const WM_CHAR As Long = &H102
  34. Private Const WM_KEYDOWN As Long = &H100
  35. Private Const WM_KEYUP As Long = &H101
  36. Private Const WM_SYSKEYDOWN As Long = &H104
  37. Private Const WM_SYSKEYUP As Long = &H105
  38. Private Const VK_LBUTTON As Long = &H1
  39. Private Const VK_RBUTTON As Long = &H2
  40. Private Const VK_CANCEL As Long = &H3
  41. Private Const VK_MBUTTON As Long = &H4
  42. Private Const VK_XBUTTON1 As Long = &H5
  43. Private Const VK_XBUTTON2 As Long = &H6
  44. Private Const VK_BACKSPACE As Long = &H8
  45. Private Const VK_TAB As Long = &H9 'TAB
  46. Private Const VK_CLEAR As Long = &HC
  47. Private Const VK_ENTER As Long = &HD
  48. Private Const VK_SHIFT As Long = &H10
  49. Private Const VK_CONTROL As Long = &H11 'CTRL
  50. Private Const VK_MENU As Long = &H12
  51. Private Const VK_PAUSE As Long = &H13
  52. Private Const VK_CAPSLOCK As Long = &H14
  53. Private Const VK_ESCAPE As Long = &H1B
  54. Private Const VK_SPACE As Long = &H20
  55. Private Const VK_PAGEUP As Long = &H21
  56. Private Const VK_PAGEDOWN As Long = &H22
  57. Private Const VK_END As Long = &H23
  58. Private Const VK_HOME As Long = &H24
  59. Private Const VK_LEFT As Long = &H25
  60. Private Const VK_UP As Long = &H26
  61. Private Const VK_RIGHT As Long = &H27
  62. Private Const VK_DOWN As Long = &H28
  63. Private Const VK_PRINTSCREEN As Long = &H2C
  64. Private Const VK_INSERT As Long = &H2D
  65. Private Const VK_DELETE As Long = &H2E
  66. Private Const VK_0 As Long = &H30
  67. Private Const VK_1 As Long = &H31
  68. Private Const VK_2 As Long = &H32
  69. Private Const VK_3 As Long = &H33
  70. Private Const VK_4 As Long = &H34
  71. Private Const VK_5 As Long = &H35
  72. Private Const VK_6 As Long = &H36
  73. Private Const VK_7 As Long = &H37
  74. Private Const VK_8 As Long = &H38
  75. Private Const VK_9 As Long = &H39
  76. Private Const VK_A As Long = &H41
  77. Private Const VK_B As Long = &H42
  78. Private Const VK_C As Long = &H43
  79. Private Const VK_D As Long = &H44
  80. Private Const VK_E As Long = &H45
  81. Private Const VK_F As Long = &H46
  82. Private Const VK_G As Long = &H47
  83. Private Const VK_H As Long = &H48
  84. Private Const VK_I As Long = &H49
  85. Private Const VK_J As Long = &H4A
  86. Private Const VK_K As Long = &H4B
  87. Private Const VK_L As Long = &H4C
  88. Private Const VK_M As Long = &H4D
  89. Private Const VK_N As Long = &H4E
  90. Private Const VK_O As Long = &H4F
  91. Private Const VK_P As Long = &H50
  92. Private Const VK_Q As Long = &H51
  93. Private Const VK_R As Long = &H52
  94. Private Const VK_S As Long = &H53
  95. Private Const VK_T As Long = &H54
  96. Private Const VK_U As Long = &H55
  97. Private Const VK_V As Long = &H56
  98. Private Const VK_W As Long = &H57
  99. Private Const VK_X As Long = &H58
  100. Private Const VK_Y As Long = &H59
  101. Private Const VK_Z As Long = &H5A
  102. Private Const VK_F11 = &H7A
  103. Private Const INPUT_KEYBOARD As Long = 1
  104. Private Const KEYEVENTF_KEYUP As Long = 2
  105. Const GW_CHILD = 5
  106. Const GW_HWNDNEXT = 2
  107. Dim keyInput() As INPUT_
  108. Dim sizeINPUT As Long
  109. Private Type INPUT_ ' typedef struct tagINPUT {
  110. dwType As Long ' DWORD type;
  111. wVK As Integer ' union {MOUSEINPUT mi;
  112. wScan As Integer ' KEYBDINPUT ki;
  113. dwFlags As Long ' HARDWAREINPUT hi;
  114. dwTime As LongPtr ' };
  115. dwExtraInfo As LongPtr ' }INPUT, *PINPUT;
  116. dwPadding As Currency ' 8 extra bytes, because mouses take more.
  117. End Type
  118. Sub main() ' {
  119. sizeINPUT = LenB(keyInput(0))
  120. Call SendKeystrokeFromExcel
  121. Call Sleep(100)
  122. Call Ctrl_H
  123. End Sub ' }
  124. Sub SendKeystrokeFromExcel()
  125. Dim hWnd As LongPtr
  126. ' Find the window by its title
  127. hWnd = 1378908 'Handle of Google Chrome
  128. ShowWindow hWnd, SW_SHOWNORMAL
  129. SetForegroundWindow hWnd
  130. Sleep (100)
  131. SendMessage hWnd, WM_KEYDOWN, VK_F11, 0
  132. End Sub
  133. Sub Ctrl_H()
  134. ReDim keyInput(0 To 3)
  135. keyInput(0).dwType = INPUT_KEYBOARD
  136. keyInput(0).dwFlags = 0 ' Press key
  137. keyInput(0).wVK = VK_CONTROL
  138. keyInput(1).dwType = INPUT_KEYBOARD
  139. keyInput(1).dwFlags = 0 ' Press key
  140. keyInput(1).wVK = VK_H
  141. keyInput(2).dwType = INPUT_KEYBOARD
  142. keyInput(2).dwFlags = KEYEVENTF_KEYUP
  143. keyInput(2).wVK = VK_H
  144. keyInput(3).dwType = INPUT_KEYBOARD
  145. keyInput(3).dwFlags = KEYEVENTF_KEYUP
  146. keyInput(3).wVK = VK_CONTROL
  147. Call SendInput(4, keyInput(0), sizeINPUT)
  148. End Sub

So when I run the code, it found the Chrome windows easily. However when it comes to run the SUB Ctrl_H(), it seems that it cant be run even enormous the amount of work I put in. All the code I found in the internet, include in stack exchange (https://stackoverflow.com/questions/13896658/sendinput-vb-basic-example) won't work . If anyone have any solution, I would be really aprreciate.

答案1

得分: 1

以下是您提供的内容的翻译:

这些是我最近项目中的声明和类型 - 它们已经在测试中运行正常。 (如果您不知道您的声明是否有效,从类似于CtrlH的东西开始是相当冒险的。CtrlH之所以不能产生您期望的结果,原因有很多 - 我建议您从在记事本中输入一个字符开始(以测试声明是否有效) - 只需在调用字符键按下的sendinput之前设置一个5秒的休眠计时器,手动选择记事本并查看发生了什么(这样您就可以排除其他可能是问题的因素)。

也许问题在于声明,也许是窗口的激活,也许是CtrlH本身的问题,一次性测试一切,您将无法真正看到哪些工作,哪些可能引起问题。

  1. Public Declare PtrSafe Function SendMouseInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_mouse, ByVal cbSize As Integer) As Long
  2. Public Declare PtrSafe Function SendKeybdInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_keybd, ByVal cbSize As Integer) As Long
  3. Type tagMOUSEINPUT
  4. dx As Long
  5. dy As Long
  6. mouseData As Long
  7. dwFlags As Long
  8. time As Long
  9. dwExtraInfo As LongPtr
  10. End Type
  11. Type tagKEYBDINPUT
  12. wVk As Integer
  13. wScan As Integer
  14. dwFlags As Long
  15. time As Long
  16. dwExtraInfo As LongPtr
  17. padding As Currency '添加8字节以达到与MOUSEINPUT相同的大小(每个Int类型参数差异2字节,少一个参数差异4字节)
  18. End Type
  19. Type tagINPUT_mouse
  20. INPUTTYPE As Long
  21. mi As tagMOUSEINPUT
  22. End Type
  23. Type tagINPUT_keybd
  24. INPUTTYPE As Long
  25. ki As tagKEYBDINPUT
  26. End Type

希望这对您有所帮助。

英文:

Those are the Declarations and Types in a recent project of mine - they work and have been tested. (Starting with something like CtrlH is pretty risky if you don't know if your declarations even work. CtrlH couldn't yield your desired result for a multitude of reasons - I would suggest you start with something like typing one character into notepad (in order to test if the declarations work) - Just set a sleep timer for 5 sec before you call sendinput for the character key press, select notepad manually and see what happens (this way you elimante other factors that could be the issue)

Maybe the issue is the Declarations, maybe it is the activation of the window, maybe it is something with CtrlH itself, By testing everything at once you won't really be able to see what works and what might be causing issues.

  1. Public Declare PtrSafe Function SendMouseInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_mouse, ByVal cbSize As Integer) As Long
  2. Public Declare PtrSafe Function SendKeybdInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_keybd, ByVal cbSize As Integer) As Long
  3. Type tagMOUSEINPUT
  4. dx As Long
  5. dy As Long
  6. mouseData As Long
  7. dwFlags As Long
  8. time As Long
  9. dwExtraInfo As LongPtr
  10. End Type
  11. Type tagKEYBDINPUT
  12. wVk As Integer
  13. wScan As Integer
  14. dwFlags As Long
  15. time As Long
  16. dwExtraInfo As LongPtr
  17. padding As Currency 'adding 8bytes to get to same size as MOUSEINPUT (2bytes difference per parameter of type Int, and 4bytes for 1 less parameter)
  18. End Type
  19. Type tagINPUT_mouse
  20. INPUTTYPE As Long
  21. mi As tagMOUSEINPUT
  22. End Type
  23. Type tagINPUT_keybd
  24. INPUTTYPE As Long
  25. ki As tagKEYBDINPUT
  26. End Type

答案2

得分: 0

基于@Lord-JulianXLII的代码,我成功编写了一个发送输入到Windows的代码。以下是代码,供有兴趣的任何人使用。

  1. Public Declare PtrSafe Function SendMouseInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_mouse, ByVal cbSize As Integer) As Long
  2. Public Declare PtrSafe Function SendKeybdInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_keybd, ByVal cbSize As Integer) As Long
  3. Type tagMOUSEINPUT
  4. dx As Long
  5. dy As Long
  6. mouseData As Long
  7. dwFlags As Long
  8. time As Long
  9. dwExtraInfo As LongPtr
  10. End Type
  11. Type tagKEYBDINPUT
  12. wVk As Integer
  13. wScan As Integer
  14. dwFlags As Long
  15. time As Long
  16. dwExtraInfo As LongPtr
  17. padding As Currency '添加 8 字节以与 MOUSEINPUT 的大小相同(每个 Int 类型的参数差 2 字节,1 个参数少了 4 字节)
  18. End Type
  19. Type tagINPUT_mouse
  20. INPUTTYPE As Long
  21. mi As tagMOUSEINPUT
  22. End Type
  23. Type tagINPUT_keybd
  24. INPUTTYPE As Long
  25. ki As tagKEYBDINPUT
  26. End Type
  27. Sub Ctrl_H()
  28. Dim inputArray(1 To 2) As tagINPUT_keybd
  29. ' 设置第一个输入结构以按下“Ctrl”键
  30. inputArray(1).INPUTTYPE = 1 ' INPUT_KEYBOARD
  31. inputArray(1).ki.wVk = VK_CONTROL
  32. inputArray(1).ki.dwFlags = 0 ' 按键按下
  33. ' 设置第二个输入结构以按下“H”键
  34. inputArray(2).INPUTTYPE = 1 ' INPUT_KEYBOARD
  35. inputArray(2).ki.wVk = VK_H
  36. inputArray(2).ki.dwFlags = 0 ' 按键按下
  37. ' 发送按下事件
  38. Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
  39. ' 设置第一个输入结构以释放“Ctrl”键
  40. inputArray(1).ki.dwFlags = KEYEVENTF_KEYUP ' 按键释放
  41. ' 设置第二个输入结构以释放“H”键
  42. inputArray(2).ki.dwFlags = KEYEVENTF_KEYUP ' 按键释放
  43. ' 发送释放事件
  44. Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
  45. End Sub

不过,如@IInspectable建议的那样,更好的方法是从UI自动化开始。

英文:

Based on @Lord-JulianXLII code, I have successfully writen a code that send input to Windows. Here is it for anyone who care

  1. Public Declare PtrSafe Function SendMouseInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_mouse, ByVal cbSize As Integer) As Long
  2. Public Declare PtrSafe Function SendKeybdInput Lib "user32.dll" Alias "SendInput" (ByVal cInputs As Long, ByRef pInputs As tagINPUT_keybd, ByVal cbSize As Integer) As Long
  3. Type tagMOUSEINPUT
  4. dx As Long
  5. dy As Long
  6. mouseData As Long
  7. dwFlags As Long
  8. time As Long
  9. dwExtraInfo As LongPtr
  10. End Type
  11. Type tagKEYBDINPUT
  12. wVk As Integer
  13. wScan As Integer
  14. dwFlags As Long
  15. time As Long
  16. dwExtraInfo As LongPtr
  17. padding As Currency 'adding 8bytes to get to same size as MOUSEINPUT (2bytes difference per parameter of type Int, and 4bytes for 1 less parameter)
  18. End Type
  19. Type tagINPUT_mouse
  20. INPUTTYPE As Long
  21. mi As tagMOUSEINPUT
  22. End Type
  23. Type tagINPUT_keybd
  24. INPUTTYPE As Long
  25. ki As tagKEYBDINPUT
  26. End Type
  27. Sub Ctrl_H()
  28. Dim inputArray(1 To 2) As tagINPUT_keybd
  29. ' Set up the first input structure for "Ctrl" key press
  30. inputArray(1).INPUTTYPE = 1 ' INPUT_KEYBOARD
  31. inputArray(1).ki.wVk = VK_CONTROL
  32. inputArray(1).ki.dwFlags = 0 ' Key press
  33. ' Set up the second input structure for "H" key press
  34. inputArray(2).INPUTTYPE = 1 ' INPUT_KEYBOARD
  35. inputArray(2).ki.wVk = VK_H
  36. inputArray(2).ki.dwFlags = 0 ' Key press
  37. ' Send the keydown events
  38. Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
  39. ' Set up the first input structure for "Ctrl" key release
  40. inputArray(1).ki.dwFlags = KEYEVENTF_KEYUP ' Key release
  41. ' Set up the second input structure for "H" key release
  42. inputArray(2).ki.dwFlags = KEYEVENTF_KEYUP ' Key release
  43. ' Send the keyup events
  44. Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
  45. End Sub

It is, however, better start with UIautomation like @IInspectable suggested.

huangapple
  • 本文由 发表于 2023年6月5日 00:39:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76401425.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定