-
Jan 20th, 2014, 07:44 AM
#1
Thread Starter
Member
SendInput - Function to type ASCII characters - where's the flaw?
Dear friends,
I need to fill a "File Open" dialog box with a string (file path and name).
Since my language has plenty of characters on the extended ASCII - for instance, a file can be named "C:\Hipóteses\Ações de mínima freqüência.doc", i thought of sending all characters in the format "Alt+000" instead of mapping each keyboard combination that produces it. The code to do this follows at the end.
However, this combination doesn't seem to work. I tested it upon a TextBox, and it caught KeyDown and KeyUp events correctly, but the due character doesn't appear . Can any of you friends spot the reason?
Thank you very much!
(My specs: VS/VB 2010, .NET 4.0, Windows 8)
vb Code:
Imports System.Runtime.InteropServices Namespace WinApi Module WinApi Public Function TypeAscii(ByVal code As Integer) As Boolean Dim kc = 96 + (code \ 100) ' key from numeric keyboard, for 1st digit of ASCII code Dim kd = 96 + ((code Mod 100) \ 10) ' key from numeric keyboard, for 2nd digit of ASCII code Dim ku = 96 + (code Mod 10) ' key from numeric keyboard, for 3rd digit of ASCII code Return SendSingleInput(InputKeyDown(18)) AndAlso SendSingleInput(InputKeyDown(kc)) AndAlso SendSingleInput(InputKeyUp(kc)) AndAlso SendSingleInput(InputKeyDown(kd)) AndAlso SendSingleInput(InputKeyUp(kd)) AndAlso SendSingleInput(InputKeyDown(ku)) AndAlso SendSingleInput(InputKeyUp(ku)) AndAlso SendSingleInput(InputKeyUp(18)) End Function Private Function SendSingleInput(ByVal single_input As INPUT) As Boolean Return CBool(SendInput(1, single_input, Marshal.SizeOf(single_input))) Application.DoEvents() End Function Private Function InputKeyDown(ByVal wVk As Short) As INPUT Dim i As INPUT i.type = INPUT_KEYBOARD i.u.ki.wVk = wVk i.u.ki.dwFlags = KEYEVENTF_KEYDOWN Return i End Function Private Function InputKeyUp(ByVal wVk As Short) As INPUT Dim i As INPUT i.type = INPUT_KEYBOARD i.u.ki.wVk = wVk i.u.ki.dwFlags = KEYEVENTF_KEYUP Return i End Function ' From here on, it's not "my" code, but code taken from Pinvoke.net and other places <DllImport("user32.dll", SetLastError:=True)> _ Private Function SendInput(ByVal cInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer End Function Structure INPUT Public type As Integer Public u As InputUnion End Structure Private Const KEYEVENTF_KEYDOWN As Integer = &H0 Private Const KEYEVENTF_EXTENDEDKEY As Integer = &H1 Private Const KEYEVENTF_KEYUP As Integer = &H2 Private Const KEYEVENTF_UNICODE As Integer = &H4 Private Const KEYEVENTF_SCANCODE As Integer = &H8 Private Const INPUT_MOUSE As Integer = 0 Private Const INPUT_KEYBOARD As Integer = 1 Private Const INPUT_HARDWARE As Integer = 2 <StructLayout(LayoutKind.Explicit)> _ Structure InputUnion <FieldOffset(0)> Public mi As MOUSEINPUT <FieldOffset(0)> Public ki As KEYBDINPUT <FieldOffset(0)> Public hi As HARDWAREINPUT End Structure 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 Const MOUSEEVENTF_MOVE = &H1 Private Const MOUSEEVENTF_LEFTDOWN = &H2 Private Const MOUSEEVENTF_LEFTUP = &H4 Private Const MOUSEEVENTF_RIGHTDOWN = &H8 Private Const MOUSEEVENTF_RIGHTUP = &H10 Private Const MOUSEEVENTF_MIDDLEDOWN = &H20 Private Const MOUSEEVENTF_MIDDLEUP = &H40 Private Const MOUSEEVENTF_ABSOLUTE = &H8000 Structure KEYBDINPUT Public wVk As Short Public wScan As Short Public dwFlags As Integer Public time As Integer Public dwExtraInfo As IntPtr End Structure Structure HARDWAREINPUT Public uMsg As Integer Public wParamL As Short Public wParamH As Short End Structure End Module End Namespace
VBobCat
VS2013 & Office-VBA
Autodidact, part-time programmer for job needs
-
Jan 23rd, 2014, 12:49 PM
#2
Re: SendInput - Function to type ASCII characters - where's the flaw?
Not sure what the solution is but I normally avoid "sendkey" type solutions.
Have you tried using sendmessage to send the text directly to the control instead?
I tried SendMessageW and SetWindowTextUnicode as declared below, seems fine but found many ways to declare this API online.
Quick test using open dialog from notepad in Win7..
Code:
Imports System.Runtime.InteropServices
Public Class Form1
Private stringToSend As String = "C:\Hipóteses\Ações de mínima freqüência.doc"
Private Const WM_SETTEXT As Integer = &HC
<DllImport("user32.dll", EntryPoint:="SendMessageW")>
Private Shared Function SendMessageW(hWnd As IntPtr, Msg As UInt32, ByVal wParam As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> lParam As String) As IntPtr
End Function
'
'<DllImport("user32.dll", EntryPoint:="SendMessageW", CharSet:=CharSet.Unicode)> _
'Private Shared Function SetWindowTextUnicode(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
'End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, EntryPoint:="FindWindow")> _
Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
' NOTE: Tested on Windows 7(US EN) with an "Open" dialog window open from windows Notepad.
' Used MS SPY++ to figure window, control tree, classnames, etc...
' find the Open dialog window.
Dim hWndOpenDialog As IntPtr = FindWindow("#32770", "Open")
If hWndOpenDialog = IntPtr.Zero Then
MessageBox.Show("Open dialog window not found!")
Return
Else
' open dialog window found, get handle to combo box parent/container
Dim hWndComboParent = FindWindowEx(hWndOpenDialog, IntPtr.Zero, "ComboBoxEx32", Nothing)
If hWndComboParent <> IntPtr.Zero Then
' get handle to combo
Dim hWndComboBox = FindWindowEx(hWndComboParent, IntPtr.Zero, "ComboBox", Nothing)
If hWndComboBox <> IntPtr.Zero Then
' get handle to the "edit" control (where file paths are entered)
Dim hWndEditBox = FindWindowEx(hWndComboBox, IntPtr.Zero, "Edit", Nothing)
If hWndEditBox <> IntPtr.Zero Then
' send our text to edit control
SendMessageW(hWndEditBox, WM_SETTEXT, IntPtr.Zero, stringToSend)
' all done.
Else
MessageBox.Show("Edit box not found!")
End If
Else
MessageBox.Show("Combo not found!")
End If
Else
MessageBox.Show("Combo parent not found!")
End If
End If
End Sub
End Class
Last edited by Edgemeal; Jan 23rd, 2014 at 01:47 PM.
-
Jan 24th, 2014, 05:07 PM
#3
Thread Starter
Member
Re: SendInput - Function to type ASCII characters - where's the flaw?
Lots of Thanks! I'm still developing these interactions and the functions you've mentioned could come in handy, I'll take a closer look on the documentation for each one of them.
In my case, in order to solve quickly my problem, I have mapped all the key combinations that my keyboard can do (yes, long and boring way), and they cover most of the characters one can use for a filename (although not all, which can be a problem).
The issue that remains intriguing me is that all those key combinations work fine, but those relying on numeric keyboard (to simulate strokes equivalent to Alt+000 or Alt+0000) don't produce the expected character (neither any character at all), regardless of the keydown and keyup events be correctly and orderly catched when I test them.
Here's the resulting code, in case you folks would bother to take a look on it:
vb Code:
Namespace WinApi Module WinApi Public Function TypeString(ByVal text As String) As Boolean For Each c In text If Not TypeKeySeq(CharToKeys(Asc(c))) Then Return False Next Return True End Function Public Function TypeKeySeq(ByVal ParamArray keys() As Integer) As Boolean For Each k In keys If Not SendSingleInput(InputKey(Short.Parse(k))) Then Return False Next Return True End Function Private Function InputKey(ByVal signaled_wVk As Short) As INPUT Dim i As INPUT i.type = INPUT_KEYBOARD i.u.ki.wVk = IIf(signaled_wVk < 0, -signaled_wVk, signaled_wVk) i.u.ki.dwFlags = IIf(signaled_wVk < 0, KEYEVENTF_KEYUP, KEYEVENTF_KEYDOWN) Return i End Function Private Function SendSingleInput(ByVal single_input As INPUT) As Boolean Return CBool(SendInput(1, single_input, Marshal.SizeOf(single_input))) Application.DoEvents() End Function Private Function CharToKeys(ByVal char_code As Integer) As Integer() Select Case char_code Case 9, 13, 27, 32, 48 To 57 : Return {char_code, -char_code} ' Case 33 : Return {16, 49, -49, -16} Case 34 : Return {16, 192, -192, -16} Case 35 : Return {16, 51, -51, -16} Case 36 : Return {16, 52, -52, -16} Case 37 : Return {16, 53, -53, -16} Case 38 : Return {16, 55, -55, -16} Case 39 : Return {192, -192} Case 40 : Return {16, 57, -57, -16} Case 41 : Return {16, 48, -48, -16} Case 42 : Return {16, 56, -56, -16} Case 43 : Return {16, 187, -187, -16} ' Case 44 To 46 : Return {char_code + 144, -(char_code + 144)} ' Case 47 : Return {193, -193} Case 58 : Return {16, 191, -191, -16} Case 59 : Return {191, -191} Case 60 : Return {16, 188, -188, -16} Case 61 : Return {187, -187} Case 62 : Return {16, 190, -190, -16} Case 63 : Return {16, 193, -193, -16} Case 64 : Return {16, 50, -50, -16} ' Case 65 To 90 : Return {16, char_code, -char_code, -16} ' Case 91 : Return {221, -221} Case 92 : Return {226, -226} Case 93 : Return {220, -220} Case 94 : Return {16, 222, -222, -16, 32, -32} Case 95 : Return {16, 189, -189, -16} Case 96 : Return {16, 219, -219, -16, 32, -32} ' Case 97 To 122 : Return {char_code - 32, -(char_code - 32)} ' Case 123 : Return {16, 221, -221, -16} Case 124 : Return {16, 226, -226, -16} Case 125 : Return {16, 220, -220, -16} Case 126 : Return {222, -222, 32, -32} ' Case 162 : Return {17, 18, 53, -53, -18, -17} Case 163 : Return {17, 18, 52, -52, -18, -17} ' Case 167 : Return {17, 18, 187, -187, -18, -17} ' Case 170 : Return {17, 18, 221, -221, -18, -17} ' Case 172 : Return {17, 18, 54, -54, -18, -17} ' Case 176 : Return {17, 18, 193, -193, -18, -17} ' Case 178 : Return {17, 18, 50, -50, -18, -17} Case 179 : Return {17, 18, 51, -51, -18, -17} ' Case 185 : Return {17, 18, 49, -49, -18, -17} Case 186 : Return {17, 18, 220, -220, -18, -17} ' Case 192 : Return {16, 219, -219, 65, -65, -16} Case 193 : Return {219, -219, 16, 65, -65, -16} Case 194 : Return {16, 222, -222, 65, -65, -16} Case 195 : Return {222, -222, 16, 65, -65, -16} Case 196 : Return {16, 54, -54, 65, -65, -16} ' Case 199 : Return {16, 186, -186, -16} Case 200 : Return {16, 219, -219, 69, -69, -16} Case 201 : Return {219, -219, 16, 69, -69, -16} Case 202 : Return {16, 222, -222, 69, -69, -16} Case 203 : Return {16, 54, -54, 69, -69, -16} Case 204 : Return {16, 219, -219, 73, -73, -16} Case 205 : Return {219, -219, 16, 73, -73, -16} Case 206 : Return {16, 222, -222, 73, -73, -16} Case 207 : Return {16, 54, -54, 73, -73, -16} ' Case 209 : Return {222, -222, 16, 78, -78, -16} Case 210 : Return {16, 219, -219, 79, -79, -16} Case 211 : Return {219, -219, 16, 79, -79, -16} Case 212 : Return {16, 222, -222, 79, -79, -16} Case 213 : Return {222, -222, 16, 79, -79, -16} Case 214 : Return {16, 54, -54, 79, -79, -16} ' Case 217 : Return {16, 219, -219, 85, -85, -16} Case 218 : Return {219, -219, 16, 85, -85, -16} Case 219 : Return {16, 222, -222, 85, -85, -16} Case 220 : Return {16, 54, -54, 85, -85, -16} ' Case 224 : Return {16, 219, -219, -16, 65, -65} Case 225 : Return {219, -219, 16, -16, 65, -65} Case 226 : Return {16, 222, -222, -16, 65, -65} Case 227 : Return {222, -222, 16, -16, 65, -65} Case 228 : Return {16, 54, -54, -16, 65, -65} ' Case 231 : Return {186, -186} Case 232 : Return {16, 219, -219, -16, 69, -69} Case 233 : Return {219, -219, 69, -69} Case 234 : Return {16, 222, -222, -16, 69, -69} Case 235 : Return {16, 54, -54, -16, 69, -69} Case 236 : Return {16, 219, -219, -16, 73, -73} Case 237 : Return {219, -219, 73, -73} Case 238 : Return {16, 222, -222, -16, 73, -73} Case 239 : Return {16, 54, -54, -16, 73, -73} ' Case 241 : Return {222, -222, 78, -78} Case 242 : Return {16, 219, -219, -16, 79, -79} Case 243 : Return {219, -219, 79, -79} Case 244 : Return {16, 222, -222, -16, 79, -79} Case 245 : Return {222, -222, 79, -79} Case 246 : Return {16, 54, -54, -16, 79, -79} ' Case 249 : Return {16, 219, -219, -16, 85, -85} Case 250 : Return {219, -219, 85, -85} Case 251 : Return {16, 222, -222, -16, 85, -85} Case 252 : Return {16, 54, -54, -16, 85, -85} ' Case Else : Return New Integer() {} End Select End Function <DllImport("user32.dll", SetLastError:=True)> _ Private Function SendInput(ByVal cInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer End Function End Module End Namespace
Last edited by VBobCat; Jan 24th, 2014 at 05:12 PM.
VBobCat
VS2013 & Office-VBA
Autodidact, part-time programmer for job needs
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|