英文:
How can I use SendInput function in VBA to combine keystrokes for Chrome window?
问题
Here's the translation of the code you provided:
我想在VBA中使用Windows API的Sendinput函数,将一组按键发送到窗口,例如Ctrl H发送到Chrome。我选择sendinput(),因为sendmessage不允许同时发送一组键,窗口会分别接收它们。另一方面,VBA中的SendKeys方法据说不可靠。
因此,在阅读文档并进行谷歌搜索后,我得到了这段代码:
' 以下为代码部分,不翻译
' ...
所以当我运行代码时,它轻松找到了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
Option Explicit
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd As LongPtr, ByVal hWndChild As LongPtr, _
ByVal lpszClass As String, ByVal lpszWindow As String) As LongPtr
Private Declare PtrSafe Function ShowWindow Lib "user32" _
(ByVal hWnd As LongPtr, ByVal nCmdShow As Long) As Boolean
Private Declare PtrSafe Function SetForegroundWindow Lib "user32" _
(ByVal hWnd As LongPtr) As Boolean
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" _
(ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
Private Declare PtrSafe Function GetWindow Lib "user32" _
(ByVal hWnd As LongPtr, ByVal wCmd As Long) As LongPtr
Private Declare PtrSafe Function EnumChildWindows Lib "user32" _
(ByVal hWnd As LongPtr, ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias _
"GetWindowTextA" (ByVal hWnd As LongPtr, ByVal lpWindowText As String, ByVal nMaxCount As LongPtr) As Long
Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function GetWindowTextLength Lib "user32" Alias _
"GetWindowTextLengthA" (ByVal hWnd As LongPtr) As Long
Public Declare PtrSafe Sub Sleep Lib "kernel32" _
(ByVal dwMilliseconds As LongPtr)
Private Declare PtrSafe Function SendInput Lib "user32" ( _
ByVal nInputs As LongPtr, _
ByRef pInputs As Any, _
ByVal cbSize As LongPtr) As Long
Private Const SW_SHOWNORMAL As Long = 1
Private Const WM_SETTEXT As Long = &HC
Private Const VK_RETURN As Integer = &HD
Private Const WM_CHAR As Long = &H102
Private Const WM_KEYDOWN As Long = &H100
Private Const WM_KEYUP As Long = &H101
Private Const WM_SYSKEYDOWN As Long = &H104
Private Const WM_SYSKEYUP As Long = &H105
Private Const VK_LBUTTON As Long = &H1
Private Const VK_RBUTTON As Long = &H2
Private Const VK_CANCEL As Long = &H3
Private Const VK_MBUTTON As Long = &H4
Private Const VK_XBUTTON1 As Long = &H5
Private Const VK_XBUTTON2 As Long = &H6
Private Const VK_BACKSPACE As Long = &H8
Private Const VK_TAB As Long = &H9 'TAB
Private Const VK_CLEAR As Long = &HC
Private Const VK_ENTER As Long = &HD
Private Const VK_SHIFT As Long = &H10
Private Const VK_CONTROL As Long = &H11 'CTRL
Private Const VK_MENU As Long = &H12
Private Const VK_PAUSE As Long = &H13
Private Const VK_CAPSLOCK As Long = &H14
Private Const VK_ESCAPE As Long = &H1B
Private Const VK_SPACE As Long = &H20
Private Const VK_PAGEUP As Long = &H21
Private Const VK_PAGEDOWN As Long = &H22
Private Const VK_END As Long = &H23
Private Const VK_HOME As Long = &H24
Private Const VK_LEFT As Long = &H25
Private Const VK_UP As Long = &H26
Private Const VK_RIGHT As Long = &H27
Private Const VK_DOWN As Long = &H28
Private Const VK_PRINTSCREEN As Long = &H2C
Private Const VK_INSERT As Long = &H2D
Private Const VK_DELETE As Long = &H2E
Private Const VK_0 As Long = &H30
Private Const VK_1 As Long = &H31
Private Const VK_2 As Long = &H32
Private Const VK_3 As Long = &H33
Private Const VK_4 As Long = &H34
Private Const VK_5 As Long = &H35
Private Const VK_6 As Long = &H36
Private Const VK_7 As Long = &H37
Private Const VK_8 As Long = &H38
Private Const VK_9 As Long = &H39
Private Const VK_A As Long = &H41
Private Const VK_B As Long = &H42
Private Const VK_C As Long = &H43
Private Const VK_D As Long = &H44
Private Const VK_E As Long = &H45
Private Const VK_F As Long = &H46
Private Const VK_G As Long = &H47
Private Const VK_H As Long = &H48
Private Const VK_I As Long = &H49
Private Const VK_J As Long = &H4A
Private Const VK_K As Long = &H4B
Private Const VK_L As Long = &H4C
Private Const VK_M As Long = &H4D
Private Const VK_N As Long = &H4E
Private Const VK_O As Long = &H4F
Private Const VK_P As Long = &H50
Private Const VK_Q As Long = &H51
Private Const VK_R As Long = &H52
Private Const VK_S As Long = &H53
Private Const VK_T As Long = &H54
Private Const VK_U As Long = &H55
Private Const VK_V As Long = &H56
Private Const VK_W As Long = &H57
Private Const VK_X As Long = &H58
Private Const VK_Y As Long = &H59
Private Const VK_Z As Long = &H5A
Private Const VK_F11 = &H7A
Private Const INPUT_KEYBOARD As Long = 1
Private Const KEYEVENTF_KEYUP As Long = 2
Const GW_CHILD = 5
Const GW_HWNDNEXT = 2
Dim keyInput() As INPUT_
Dim sizeINPUT As Long
Private Type INPUT_ ' typedef struct tagINPUT {
dwType As Long ' DWORD type;
wVK As Integer ' union {MOUSEINPUT mi;
wScan As Integer ' KEYBDINPUT ki;
dwFlags As Long ' HARDWAREINPUT hi;
dwTime As LongPtr ' };
dwExtraInfo As LongPtr ' }INPUT, *PINPUT;
dwPadding As Currency ' 8 extra bytes, because mouses take more.
End Type
Sub main() ' {
sizeINPUT = LenB(keyInput(0))
Call SendKeystrokeFromExcel
Call Sleep(100)
Call Ctrl_H
End Sub ' }
Sub SendKeystrokeFromExcel()
Dim hWnd As LongPtr
' Find the window by its title
hWnd = 1378908 'Handle of Google Chrome
ShowWindow hWnd, SW_SHOWNORMAL
SetForegroundWindow hWnd
Sleep (100)
SendMessage hWnd, WM_KEYDOWN, VK_F11, 0
End Sub
Sub Ctrl_H()
ReDim keyInput(0 To 3)
keyInput(0).dwType = INPUT_KEYBOARD
keyInput(0).dwFlags = 0 ' Press key
keyInput(0).wVK = VK_CONTROL
keyInput(1).dwType = INPUT_KEYBOARD
keyInput(1).dwFlags = 0 ' Press key
keyInput(1).wVK = VK_H
keyInput(2).dwType = INPUT_KEYBOARD
keyInput(2).dwFlags = KEYEVENTF_KEYUP
keyInput(2).wVK = VK_H
keyInput(3).dwType = INPUT_KEYBOARD
keyInput(3).dwFlags = KEYEVENTF_KEYUP
keyInput(3).wVK = VK_CONTROL
Call SendInput(4, keyInput(0), sizeINPUT)
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本身的问题,一次性测试一切,您将无法真正看到哪些工作,哪些可能引起问题。
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
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
Type tagMOUSEINPUT
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
End Type
Type tagKEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
padding As Currency '添加8字节以达到与MOUSEINPUT相同的大小(每个Int类型参数差异2字节,少一个参数差异4字节)
End Type
Type tagINPUT_mouse
INPUTTYPE As Long
mi As tagMOUSEINPUT
End Type
Type tagINPUT_keybd
INPUTTYPE As Long
ki As tagKEYBDINPUT
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.
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
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
Type tagMOUSEINPUT
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
End Type
Type tagKEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
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)
End Type
Type tagINPUT_mouse
INPUTTYPE As Long
mi As tagMOUSEINPUT
End Type
Type tagINPUT_keybd
INPUTTYPE As Long
ki As tagKEYBDINPUT
End Type
答案2
得分: 0
基于@Lord-JulianXLII的代码,我成功编写了一个发送输入到Windows的代码。以下是代码,供有兴趣的任何人使用。
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
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
Type tagMOUSEINPUT
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
End Type
Type tagKEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
padding As Currency '添加 8 字节以与 MOUSEINPUT 的大小相同(每个 Int 类型的参数差 2 字节,1 个参数少了 4 字节)
End Type
Type tagINPUT_mouse
INPUTTYPE As Long
mi As tagMOUSEINPUT
End Type
Type tagINPUT_keybd
INPUTTYPE As Long
ki As tagKEYBDINPUT
End Type
Sub Ctrl_H()
Dim inputArray(1 To 2) As tagINPUT_keybd
' 设置第一个输入结构以按下“Ctrl”键
inputArray(1).INPUTTYPE = 1 ' INPUT_KEYBOARD
inputArray(1).ki.wVk = VK_CONTROL
inputArray(1).ki.dwFlags = 0 ' 按键按下
' 设置第二个输入结构以按下“H”键
inputArray(2).INPUTTYPE = 1 ' INPUT_KEYBOARD
inputArray(2).ki.wVk = VK_H
inputArray(2).ki.dwFlags = 0 ' 按键按下
' 发送按下事件
Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
' 设置第一个输入结构以释放“Ctrl”键
inputArray(1).ki.dwFlags = KEYEVENTF_KEYUP ' 按键释放
' 设置第二个输入结构以释放“H”键
inputArray(2).ki.dwFlags = KEYEVENTF_KEYUP ' 按键释放
' 发送释放事件
Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
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
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
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
Type tagMOUSEINPUT
dx As Long
dy As Long
mouseData As Long
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
End Type
Type tagKEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As LongPtr
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)
End Type
Type tagINPUT_mouse
INPUTTYPE As Long
mi As tagMOUSEINPUT
End Type
Type tagINPUT_keybd
INPUTTYPE As Long
ki As tagKEYBDINPUT
End Type
Sub Ctrl_H()
Dim inputArray(1 To 2) As tagINPUT_keybd
' Set up the first input structure for "Ctrl" key press
inputArray(1).INPUTTYPE = 1 ' INPUT_KEYBOARD
inputArray(1).ki.wVk = VK_CONTROL
inputArray(1).ki.dwFlags = 0 ' Key press
' Set up the second input structure for "H" key press
inputArray(2).INPUTTYPE = 1 ' INPUT_KEYBOARD
inputArray(2).ki.wVk = VK_H
inputArray(2).ki.dwFlags = 0 ' Key press
' Send the keydown events
Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
' Set up the first input structure for "Ctrl" key release
inputArray(1).ki.dwFlags = KEYEVENTF_KEYUP ' Key release
' Set up the second input structure for "H" key release
inputArray(2).ki.dwFlags = KEYEVENTF_KEYUP ' Key release
' Send the keyup events
Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
End Sub
It is, however, better start with UIautomation like @IInspectable suggested.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论