Results 1 to 3 of 3

Thread: SendInput - Function to type ASCII characters - where's the flaw?

  1. #1

    Thread Starter
    Member VBobCat's Avatar
    Join Date
    Sep 2011
    Location
    São Paulo, Brazil
    Posts
    34

    Question 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:
    1. Imports System.Runtime.InteropServices
    2. Namespace WinApi
    3.     Module WinApi
    4.         Public Function TypeAscii(ByVal code As Integer) As Boolean
    5.             Dim kc = 96 + (code \ 100) ' key from numeric keyboard, for 1st digit of ASCII code
    6.             Dim kd = 96 + ((code Mod 100) \ 10) ' key from numeric keyboard, for 2nd digit of ASCII code
    7.             Dim ku = 96 + (code Mod 10) ' key from numeric keyboard, for 3rd digit of ASCII code
    8.             Return SendSingleInput(InputKeyDown(18)) AndAlso
    9.                    SendSingleInput(InputKeyDown(kc)) AndAlso
    10.                    SendSingleInput(InputKeyUp(kc)) AndAlso
    11.                    SendSingleInput(InputKeyDown(kd)) AndAlso
    12.                    SendSingleInput(InputKeyUp(kd)) AndAlso
    13.                    SendSingleInput(InputKeyDown(ku)) AndAlso
    14.                    SendSingleInput(InputKeyUp(ku)) AndAlso
    15.                    SendSingleInput(InputKeyUp(18))
    16.         End Function
    17.         Private Function SendSingleInput(ByVal single_input As INPUT) As Boolean
    18.             Return CBool(SendInput(1, single_input, Marshal.SizeOf(single_input)))
    19.             Application.DoEvents()
    20.         End Function
    21.         Private Function InputKeyDown(ByVal wVk As Short) As INPUT
    22.             Dim i As INPUT
    23.             i.type = INPUT_KEYBOARD
    24.             i.u.ki.wVk = wVk
    25.             i.u.ki.dwFlags = KEYEVENTF_KEYDOWN
    26.             Return i
    27.         End Function
    28.         Private Function InputKeyUp(ByVal wVk As Short) As INPUT
    29.             Dim i As INPUT
    30.             i.type = INPUT_KEYBOARD
    31.             i.u.ki.wVk = wVk
    32.             i.u.ki.dwFlags = KEYEVENTF_KEYUP
    33.             Return i
    34.         End Function
    35.         ' From here on, it's not "my" code, but code taken from Pinvoke.net and other places
    36.         <DllImport("user32.dll", SetLastError:=True)> _
    37.         Private Function SendInput(ByVal cInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer
    38.         End Function
    39.         Structure INPUT
    40.             Public type As Integer
    41.             Public u As InputUnion
    42.         End Structure
    43.         Private Const KEYEVENTF_KEYDOWN As Integer = &H0
    44.         Private Const KEYEVENTF_EXTENDEDKEY As Integer = &H1
    45.         Private Const KEYEVENTF_KEYUP As Integer = &H2
    46.         Private Const KEYEVENTF_UNICODE As Integer = &H4
    47.         Private Const KEYEVENTF_SCANCODE As Integer = &H8
    48.         Private Const INPUT_MOUSE As Integer = 0
    49.         Private Const INPUT_KEYBOARD As Integer = 1
    50.         Private Const INPUT_HARDWARE As Integer = 2
    51.         <StructLayout(LayoutKind.Explicit)> _
    52.         Structure InputUnion
    53.             <FieldOffset(0)> Public mi As MOUSEINPUT
    54.             <FieldOffset(0)> Public ki As KEYBDINPUT
    55.             <FieldOffset(0)> Public hi As HARDWAREINPUT
    56.         End Structure
    57.         Structure MOUSEINPUT
    58.             Public dx As Integer
    59.             Public dy As Integer
    60.             Public mouseData As Integer
    61.             Public dwFlags As Integer
    62.             Public time As Integer
    63.             Public dwExtraInfo As IntPtr
    64.         End Structure
    65.         Private Const MOUSEEVENTF_MOVE = &H1
    66.         Private Const MOUSEEVENTF_LEFTDOWN = &H2
    67.         Private Const MOUSEEVENTF_LEFTUP = &H4
    68.         Private Const MOUSEEVENTF_RIGHTDOWN = &H8
    69.         Private Const MOUSEEVENTF_RIGHTUP = &H10
    70.         Private Const MOUSEEVENTF_MIDDLEDOWN = &H20
    71.         Private Const MOUSEEVENTF_MIDDLEUP = &H40
    72.         Private Const MOUSEEVENTF_ABSOLUTE = &H8000
    73.         Structure KEYBDINPUT
    74.             Public wVk As Short
    75.             Public wScan As Short
    76.             Public dwFlags As Integer
    77.             Public time As Integer
    78.             Public dwExtraInfo As IntPtr
    79.         End Structure
    80.         Structure HARDWAREINPUT
    81.             Public uMsg As Integer
    82.             Public wParamL As Short
    83.             Public wParamH As Short
    84.         End Structure
    85.     End Module
    86. End Namespace
    VBobCat
    VS2013 & Office-VBA
    Autodidact, part-time programmer for job needs

  2. #2
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    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.

  3. #3

    Thread Starter
    Member VBobCat's Avatar
    Join Date
    Sep 2011
    Location
    São Paulo, Brazil
    Posts
    34

    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:
    1. Namespace WinApi
    2.     Module WinApi
    3.         Public Function TypeString(ByVal text As String) As Boolean
    4.             For Each c In text
    5.                 If Not TypeKeySeq(CharToKeys(Asc(c))) Then Return False
    6.             Next
    7.             Return True
    8.         End Function
    9.         Public Function TypeKeySeq(ByVal ParamArray keys() As Integer) As Boolean
    10.             For Each k In keys
    11.                 If Not SendSingleInput(InputKey(Short.Parse(k))) Then Return False
    12.             Next
    13.             Return True
    14.         End Function
    15.         Private Function InputKey(ByVal signaled_wVk As Short) As INPUT
    16.             Dim i As INPUT
    17.             i.type = INPUT_KEYBOARD
    18.             i.u.ki.wVk = IIf(signaled_wVk < 0, -signaled_wVk, signaled_wVk)
    19.             i.u.ki.dwFlags = IIf(signaled_wVk < 0, KEYEVENTF_KEYUP, KEYEVENTF_KEYDOWN)
    20.             Return i
    21.         End Function
    22.         Private Function SendSingleInput(ByVal single_input As INPUT) As Boolean
    23.             Return CBool(SendInput(1, single_input, Marshal.SizeOf(single_input)))
    24.             Application.DoEvents()
    25.         End Function
    26.         Private Function CharToKeys(ByVal char_code As Integer) As Integer()
    27.             Select Case char_code
    28.                 Case 9, 13, 27, 32, 48 To 57 : Return {char_code, -char_code}
    29.                     '
    30.                 Case 33 : Return {16, 49, -49, -16}
    31.                 Case 34 : Return {16, 192, -192, -16}
    32.                 Case 35 : Return {16, 51, -51, -16}
    33.                 Case 36 : Return {16, 52, -52, -16}
    34.                 Case 37 : Return {16, 53, -53, -16}
    35.                 Case 38 : Return {16, 55, -55, -16}
    36.                 Case 39 : Return {192, -192}
    37.                 Case 40 : Return {16, 57, -57, -16}
    38.                 Case 41 : Return {16, 48, -48, -16}
    39.                 Case 42 : Return {16, 56, -56, -16}
    40.                 Case 43 : Return {16, 187, -187, -16}
    41.                     '
    42.                 Case 44 To 46 : Return {char_code + 144, -(char_code + 144)}
    43.                     '
    44.                 Case 47 : Return {193, -193}
    45.                 Case 58 : Return {16, 191, -191, -16}
    46.                 Case 59 : Return {191, -191}
    47.                 Case 60 : Return {16, 188, -188, -16}
    48.                 Case 61 : Return {187, -187}
    49.                 Case 62 : Return {16, 190, -190, -16}
    50.                 Case 63 : Return {16, 193, -193, -16}
    51.                 Case 64 : Return {16, 50, -50, -16}
    52.                     '
    53.                 Case 65 To 90 : Return {16, char_code, -char_code, -16}
    54.                     '
    55.                 Case 91 : Return {221, -221}
    56.                 Case 92 : Return {226, -226}
    57.                 Case 93 : Return {220, -220}
    58.                 Case 94 : Return {16, 222, -222, -16, 32, -32}
    59.                 Case 95 : Return {16, 189, -189, -16}
    60.                 Case 96 : Return {16, 219, -219, -16, 32, -32}
    61.                     '
    62.                 Case 97 To 122 : Return {char_code - 32, -(char_code - 32)}
    63.                     '
    64.                 Case 123 : Return {16, 221, -221, -16}
    65.                 Case 124 : Return {16, 226, -226, -16}
    66.                 Case 125 : Return {16, 220, -220, -16}
    67.                 Case 126 : Return {222, -222, 32, -32}
    68.                     '
    69.                 Case 162 : Return {17, 18, 53, -53, -18, -17}
    70.                 Case 163 : Return {17, 18, 52, -52, -18, -17}
    71.                     '
    72.                 Case 167 : Return {17, 18, 187, -187, -18, -17}
    73.                     '
    74.                 Case 170 : Return {17, 18, 221, -221, -18, -17}
    75.                     '
    76.                 Case 172 : Return {17, 18, 54, -54, -18, -17}
    77.                     '
    78.                 Case 176 : Return {17, 18, 193, -193, -18, -17}
    79.                     '
    80.                 Case 178 : Return {17, 18, 50, -50, -18, -17}
    81.                 Case 179 : Return {17, 18, 51, -51, -18, -17}
    82.                     '
    83.                 Case 185 : Return {17, 18, 49, -49, -18, -17}
    84.                 Case 186 : Return {17, 18, 220, -220, -18, -17}
    85.                     '
    86.                 Case 192 : Return {16, 219, -219, 65, -65, -16}
    87.                 Case 193 : Return {219, -219, 16, 65, -65, -16}
    88.                 Case 194 : Return {16, 222, -222, 65, -65, -16}
    89.                 Case 195 : Return {222, -222, 16, 65, -65, -16}
    90.                 Case 196 : Return {16, 54, -54, 65, -65, -16}
    91.                     '
    92.                 Case 199 : Return {16, 186, -186, -16}
    93.                 Case 200 : Return {16, 219, -219, 69, -69, -16}
    94.                 Case 201 : Return {219, -219, 16, 69, -69, -16}
    95.                 Case 202 : Return {16, 222, -222, 69, -69, -16}
    96.                 Case 203 : Return {16, 54, -54, 69, -69, -16}
    97.                 Case 204 : Return {16, 219, -219, 73, -73, -16}
    98.                 Case 205 : Return {219, -219, 16, 73, -73, -16}
    99.                 Case 206 : Return {16, 222, -222, 73, -73, -16}
    100.                 Case 207 : Return {16, 54, -54, 73, -73, -16}
    101.                     '
    102.                 Case 209 : Return {222, -222, 16, 78, -78, -16}
    103.                 Case 210 : Return {16, 219, -219, 79, -79, -16}
    104.                 Case 211 : Return {219, -219, 16, 79, -79, -16}
    105.                 Case 212 : Return {16, 222, -222, 79, -79, -16}
    106.                 Case 213 : Return {222, -222, 16, 79, -79, -16}
    107.                 Case 214 : Return {16, 54, -54, 79, -79, -16}
    108.                     '
    109.                 Case 217 : Return {16, 219, -219, 85, -85, -16}
    110.                 Case 218 : Return {219, -219, 16, 85, -85, -16}
    111.                 Case 219 : Return {16, 222, -222, 85, -85, -16}
    112.                 Case 220 : Return {16, 54, -54, 85, -85, -16}
    113.                     '
    114.                 Case 224 : Return {16, 219, -219, -16, 65, -65}
    115.                 Case 225 : Return {219, -219, 16, -16, 65, -65}
    116.                 Case 226 : Return {16, 222, -222, -16, 65, -65}
    117.                 Case 227 : Return {222, -222, 16, -16, 65, -65}
    118.                 Case 228 : Return {16, 54, -54, -16, 65, -65}
    119.                     '
    120.                 Case 231 : Return {186, -186}
    121.                 Case 232 : Return {16, 219, -219, -16, 69, -69}
    122.                 Case 233 : Return {219, -219, 69, -69}
    123.                 Case 234 : Return {16, 222, -222, -16, 69, -69}
    124.                 Case 235 : Return {16, 54, -54, -16, 69, -69}
    125.                 Case 236 : Return {16, 219, -219, -16, 73, -73}
    126.                 Case 237 : Return {219, -219, 73, -73}
    127.                 Case 238 : Return {16, 222, -222, -16, 73, -73}
    128.                 Case 239 : Return {16, 54, -54, -16, 73, -73}
    129.                     '
    130.                 Case 241 : Return {222, -222, 78, -78}
    131.                 Case 242 : Return {16, 219, -219, -16, 79, -79}
    132.                 Case 243 : Return {219, -219, 79, -79}
    133.                 Case 244 : Return {16, 222, -222, -16, 79, -79}
    134.                 Case 245 : Return {222, -222, 79, -79}
    135.                 Case 246 : Return {16, 54, -54, -16, 79, -79}
    136.                     '
    137.                 Case 249 : Return {16, 219, -219, -16, 85, -85}
    138.                 Case 250 : Return {219, -219, 85, -85}
    139.                 Case 251 : Return {16, 222, -222, -16, 85, -85}
    140.                 Case 252 : Return {16, 54, -54, -16, 85, -85}
    141.                     '
    142.                 Case Else : Return New Integer() {}
    143.             End Select
    144.         End Function
    145.         <DllImport("user32.dll", SetLastError:=True)> _
    146.         Private Function SendInput(ByVal cInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer
    147.         End Function
    148.     End Module
    149. 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
  •  



Click Here to Expand Forum to Full Width