Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

SendKeys PowerBasic replacement

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • SendKeys PowerBasic replacement

    I know that the Journal Playback Hook is the proper way to send keys to
    an application, but I have a lot of existing VB code that used their SendKeys
    command. So I built an include file to emulate this command. It will
    support all of the VB's sendkeys codes, plus I added several more codes to
    do more functions that the VB sendkeys cant. (like mouse movements, sleep, etc)

    I have tried to throughly test it, and it seems to work fine.
    If fact it even send keys to a DOS window, which I had problems with VB SendKeys.

    ADDED: AppActivate function (similar to VBs AppActivate)
    ADDED: {LMOUSECLICK X Y} to give basic mouse functions
    ADDED: {CHR 123} to send a ascii code to the window example {CHR 65} would send A

    Code:
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    '  SendKeys.inc        - by William Burns    revised 03/19/2004
    '
    '  Made with PowerBasic for Windows 7.0
    '
    '  This SendKeys function should emulate most of the same rules as the VisualBasic sendkeys
    '
    '  Example usage:   SendKeys "This is my text to send.{ENTER}"
    '
    '  You can send these codes: {ENTER}{ESC}{UP}{DOWN}{LEFT}{RIGHT}
    '  {BACKSPACE}or{BS}{HOME}{END}{PGUP}{PGDN}{TAB}{DEL}or{DELETE}
    '  {INS}or{INSERT}{WIN}{PRTSC}(CAPSLOCK}{NUMLOCK}{SCROLLLOCK}{HELP}
    '  {PAUSEKEY} {BREAK}{LCONTROL}{RCONTROL}{LSHIFT}{RSHIFT}{ATTN}
    '  {LMENU}{RMENU}
    '  {F1}-{F16}    {SLEEP 1000} <-- 1000 miliseconds
    '  {PAUSE 3.5}                <-- Pauses 3.5 seconds (while processing event messages)
    '  {AppActivate WindowName}   <-- switches to this window
    '  {LMOUSECLICK X Y}          <-- Left button mouse click at x/y screen position
    '  {RMOUSECLICK X Y}          <-- Right button mouse click at x/y screen position
    '  {MMOUSECLICK X Y}          <-- Middle button mouse click at x/y screen position
    '  {CHR 123}                  <-- Send an ascii code 123 (same as pressing Alt-123     example: {CHR 65} would be A
    '
    '  Procede characters with + for Shift, ^ for Ctrl, % for Alt                          example: ^p       would be Ctrl-p
    '  You can also group characters for shift/ctrl/alt with parentheses ()                example: %(fx)    would be Alt-F Alt-X     
    '  To send these special characters {+^%~( as plain characters enclose them in braces  example: {{}      would just send  {
    '  To send a key multiple times inclose it in braces with a number like {h 3}          example: {DEL 41)  would send DELETE key 41 times
    '
    '  I also included a routine called SendPlainText to make it easier to send plain text without
    '  worrying about enclosing the special characters in braces (this one will not process codes)
    '
    '  Note: the VB sendkeys has an optional 2nd parameter for pausing the program, but it is rarely used and
    '        since PowerBasic cant do optional parms, I left this parm off and gave you a seperate sub called
    '        WaitForNoKeys   <-- just call this sub to see if the user has let go of all the keys, then call sendkeys
    '
    '  ADDED: The code {AppActivate WindowName} will switch focus to the WindowName you specify
    '         or you can call this function direct:  Result = AppActivate("Untitled - Notepad")
    '
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    #If Not %Def(%WINAPI)
        #Include "win32api.inc"                        'add win32api if not already added
    #EndIf
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Declare Sub SendKeys(ByVal sText As String)        'main sub (should work just like VBs SendKeys command
    Declare Sub WaitForNoKeys                          'call this to wait until user lets go of all keys
    Declare Sub SendPlainText(ByVal sText As String)   'Similar to SendKeys except doesnt process codes or shifted states
    Declare Function AppActivate(ByVal sWinName As String) As Long 'sets focus to windowname
    Declare Sub SendEachKey(ByVal sChar As String, ByVal iShiftedState As Long) 'used internaly
    Declare Function SwitchToWin(ByVal iHandle As Long, ByVal iFlag As Long) As Long 'used internaly by AppActivate function
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Sub SendKeys(ByVal sText As String)
       Local iCount         As Long
       Local iCount2        As Long
       Local iShiftedState  As Long
       Local sSingleChar    As String
       If Len(sText) < 1 Then Exit Sub
       For iCount = 1 To Len(sText)
          sSingleChar = Mid$(sText,iCount,1)
          If sSingleChar = "+" And IsFalse(iShiftedState And 1) Then  'Shift
             iShiftedState = iShiftedState Or 1
             keybd_event %VK_SHIFT, MapVirtualKey(%VK_SHIFT, 0), 0, 0
             Iterate For 'get next char
          End If
          If sSingleChar = "^" And IsFalse(iShiftedState And 2) Then  'Ctrl
             iShiftedState = iShiftedState Or 2
             keybd_event %VK_CONTROL, MapVirtualKey(%VK_CONTROL, 0), 0, 0
             Iterate For 'get next char
          End If
          If sSingleChar = "%" And IsFalse(iShiftedState And 4) Then  'Alt
             iShiftedState = iShiftedState Or 4
             keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), 0, 0
             Iterate For 'get next char
          End If
          If sSingleChar = "(" And iShiftedState Then  'group of shifted keys
             For iCount2 = iCount + 1 To (InStr(iCount + 2,sText,")") -1)   'process shift/ctrl/alt grouping
                sSingleChar = Mid$(sText,iCount2,1)
                If sSingleChar = "{" Then  'process code
                   Call SendEachKey(Mid$(sText, iCount2, ((InStr(iCount2 + 2,sText,"}")-iCount2)+1)), iShiftedState) 'process codes
                   iCount2 = InStr(iCount2 + 2,sText,"}") 'set next reg char to after the bracket
                Else                       'not a code so process each char
                   Call SendEachKey(sSingleChar, iShiftedState)
                End If
             Next iCount2                  'next grouped key
             iCount = InStr(iCount + 2,sText,")")
          Else                             'not grouped, so process each code or char
             If sSingleChar = "{" Then     'process code
                Call SendEachKey(Mid$(sText, iCount, ((InStr(iCount + 2,sText,"}")-iCount)+1)), iShiftedState) 'process codes
                iCount = InStr(iCount + 2,sText,"}") 'set next reg char to after the bracket
             Else                          'not a code so process each char
                Call SendEachKey(sSingleChar, iShiftedState)
             End If
          End If
          If (iShiftedState And 1) Then keybd_event %VK_SHIFT, MapVirtualKey(%VK_SHIFT, 0), %KEYEVENTF_KEYUP, 0: Sleep 0     'key_UP msg
          If (iShiftedState And 2) Then keybd_event %VK_CONTROL, MapVirtualKey(%VK_CONTROL, 0), %KEYEVENTF_KEYUP, 0: Sleep 0 'key_UP msg
          If (iShiftedState And 4) Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), %KEYEVENTF_KEYUP, 0: Sleep 0       'key_UP msg
          iShiftedState = 0
       Next iCount
    End Sub
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Sub MouseClick(ByVal sButton As String, ByVal iXpos As Long, ByVal iYpos As Long)  'internal use
       If iXpos < 0 Or iyPos < 0 Then Exit Sub
       'mouse_event %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0 'move mouse to correct position
       SetCursorPos iXpos, iYpos 'move mouse
       Select Case sButton
          Case "L" 'left mouse button
             mouse_event %MOUSEEVENTF_LEFTDOWN Or %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0
             mouse_event %MOUSEEVENTF_LEFTUP Or %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0
          Case "R" 'right mouse button
             mouse_event %MOUSEEVENTF_RIGHTDOWN Or %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0
             mouse_event %MOUSEEVENTF_RIGHTUP Or %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0
          Case "M" 'middle mouse button
             mouse_event %MOUSEEVENTF_MIDDLEDOWN Or %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0
             mouse_event %MOUSEEVENTF_MIDDLEUP Or %MOUSEEVENTF_ABSOLUTE, iXpos, iYpos, 0, 0
       End Select
    End Sub
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Sub SendChrCode(ByVal sChar As String, ByVal iShiftedState As Long)  'internal use
       Local iRet        As Long
       Local iNumPad     As Long
       Local iCounter    As Long
       If (iShiftedState And 4) <> 4 Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), 0, 0 'press Alt
       For iCounter = 5 To Len(sChar) -1
          If Asc(sChar,iCounter) > 47 And Asc(sChar,iCounter) < 58 Then  'only process chars 0 - 9
             iNumPad = Val(Mid$(sChar,iCounter,1)) + &H60          'convert each number to the correct keypad scan code
             keybd_event iNumPad, MapVirtualKey(iNumPad, 0), 0, 0  'press keypad      
             keybd_event iNumPad, MapVirtualKey(iNumPad, 0), %KEYEVENTF_KEYUP, 0: Sleep 0 'key_UP msg
          End If
       Next iCounter
       If (iShiftedState And 4) <> 4 Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), %KEYEVENTF_KEYUP, 0: Sleep 0       'key_UP msg
    End Sub
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Sub SendEachKey(ByVal sChar As String, ByVal iShiftedState As Long)  'internal use
       Local iCounter       As Long
       Local iTime          As Single
       Local iRet           As Long
       Local iVKcode        As Integer
       Local iTempShifted   As Long
       Local iRepeat        As Single
       If Len(sChar) < 1 Then Exit Sub
       iVKcode = 0
       iRepeat = 1
       If sChar = "~" Then iVKcode = %VK_RETURN  ' ~ is enter key
       If Len(sChar) > 1 And Left$(sChar,1) = "{" Then
             If ParseCount(sChar," ") > 1 Then   'second parm is included
                If UCase$(Parse$(sChar," ",1)) = "{APPACTIVATE" Then 'switch window code
                   Call AppActivate(Mid$(sChar, 14,(Len(sChar)-14)))
                   Exit Sub
                End If
                If UCase$(Parse$(sChar," ",1)) = "{LMOUSECLICK" Or UCase$(Parse$(sChar," ",1)) = "{RMOUSECLICK" Or UCase$(Parse$(sChar," ",1)) = "{MMOUSECLICK" Then 'mouseclick
                   Call MouseClick(UCase$(Mid$(sChar,2,1)),Val(Parse$(sChar," ",2)), Val(Parse$(sChar," ",3)))
                   Exit Sub
                End If
                If UCase$(Parse$(sChar," ",1)) = "{CHR" Then 'CHR code use Alt numpad
                   SendChrCode(sChar,iShiftedState)
                   Exit Sub
                End If
                iRepeat = Val(Left$(Parse$(sChar," ",2),Len(Parse$(sChar," ",2))-1)) 'grab repeat number only
                sChar = Parse$(sChar," ",1) + "}"'now set the work string to be real code
             End If
             Select Case UCase$(sChar)
                Case "{ENTER}"
                   iVKcode = %VK_RETURN
                Case "{TAB}"
                   iVKcode = %VK_TAB
                Case "{LMOUSECLICK}"
                   iVKcode = %VK_LBUTTON
                Case "{RMOUSECLICK}"
                   iVKcode = %VK_RBUTTON
                Case "{BACKSPACE}", "{BS}"
                   iVKcode = %VK_BACK
                Case "{RIGHT}"
                   iVKcode = %VK_RIGHT
                Case "{LEFT}"
                   iVKcode = %VK_LEFT
                Case "{UP}"
                   iVKcode = %VK_UP
                Case "{DOWN}"
                   iVKcode = %VK_DOWN
                Case "{HOME}"
                   iVKcode = %VK_HOME
                Case "{END}"
                   iVKcode = %VK_END
                Case "{PGDN}"
                   iVKcode = %VK_PGDN
                Case "{PGUP}"
                   iVKcode = %VK_PGUP
                Case "{INS}", "{INSERT}"
                   iVKcode = %VK_INSERT
                Case "{DEL}", "{DELETE}"
                   iVKcode = %VK_DELETE
                Case "{ESC}"
                   iVKcode = %VK_ESCAPE
                Case "{F1}"
                   iVKcode = %VK_F1
                Case "{F2}"
                   iVKcode = %VK_F2
                Case "{F3}"
                   iVKcode = %VK_F3
                Case "{F4}"
                   iVKcode = %VK_F4
                Case "{F5}"
                   iVKcode = %VK_F5
                Case "{F6}"
                   iVKcode = %VK_F6
                Case "{F7}"
                   iVKcode = %VK_F7
                Case "{F8}"
                   iVKcode = %VK_F8
                Case "{F9}"
                   iVKcode = %VK_F9
                Case "{F10}"
                   iVKcode = %VK_F10
                Case "{F11}"
                   iVKcode = %VK_F11
                Case "{F12}"
                   iVKcode = %VK_F12
                Case "{F13}"
                   iVKcode = %VK_F13
                Case "{F14}"
                   iVKcode = %VK_F14
                Case "{F15}"
                   iVKcode = %VK_F15
                Case "{F16}"
                   iVKcode = %VK_F16
                Case "{PRTSC}"
                   iVKcode = %VK_SNAPSHOT
                Case "{WIN}"
                   iVKcode = %VK_LWIN
                Case "{CAPSLOCK}"
                   iVKcode = %VK_CAPITAL
                Case "{NUMLOCK}"
                   iVKcode = %VK_NUMLOCK
                Case "{SCROLLLOCK}"
                   iVKcode = %VK_SCROLL
                Case "{LCONTROL}"
                   iVKcode = %VK_LCONTROL
                Case "{RCONTROL}"
                   iVKcode = %VK_RCONTROL
                Case "{LSHIFT}"
                   iVKcode = %VK_LSHIFT
                Case "{RSHIFT}"
                   iVKcode = %VK_RSHIFT
                Case "{LMENU}"
                   iVKcode = %VK_LMENU
                Case "{RMENU}"
                   iVKcode = %VK_RMENU
                Case "{ATTN}"
                   iVKcode = %VK_ATTN
                Case "{BREAK}"
                   iVKcode = %VK_CANCEL
                Case "{PAUSEKEY}"
                   iVKcode = %VK_PAUSE
                Case "{NOTHING}"              'added so you can use Alt while typing nothing ex: %{NOTHING}
                   Exit Sub
                Case "{HELP}"
                   iVKcode = %VK_HELP
                Case "{SLEEP}"                'suggested by Eros Olmi
                   Sleep iRepeat
                   Exit Sub
                Case "{PAUSE}"                'sleeps nicely while processing events
                   iTime = Timer
                   Do While Timer < (iTime + iRepeat)
                      Sleep 100
                      Dialog DoEvents
                   Loop
                   Exit Sub
                Case Else
                   sChar = Mid$(sChar,2,1)    'special char to send as normal key
             End Select
       End If
       If iVKcode = 0 Then                    'process normal keys
          iRet = VkKeyScan(Asc(sChar))
          If (LoByt(iRet) = -1) And (HiByt(iRet) = -1) Then Exit Sub 'cant do this char so skip
          iVKcode = LoByt(iRet)
          If (iShiftedState And HiByt(iRet)) <> HiByt(iRet) Then iTempShifted = HiByt(iRet) - (iShiftedState And HiByt(iRet)) 'and temp shift state if needed for this key
       End If
       If (iTempShifted And 1) Then keybd_event %VK_SHIFT, MapVirtualKey(%VK_SHIFT, 0), 0, 0     'hold down shift
       If (iTempShifted And 2) Then keybd_event %VK_CONTROL, MapVirtualKey(%VK_CONTROL, 0), 0, 0 'hold down control
       If (iTempShifted And 4) Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), 0, 0       'hold down alt
       Do
          keybd_event iVKcode, MapVirtualKey(iVKcode, 0), 0, 0 :Sleep 0               'key_down msg
          keybd_event iVKcode, MapVirtualKey(iVKcode, 0), %KEYEVENTF_KEYUP, 0 :Sleep 0'key_up msg
          Decr iRepeat
       Loop While iRepeat > 0
       If (iTempShifted And 1) Then keybd_event %VK_SHIFT, MapVirtualKey(%VK_SHIFT, 0), %KEYEVENTF_KEYUP, 0: Sleep 0     'key_UP msg
       If (iTempShifted And 2) Then keybd_event %VK_CONTROL, MapVirtualKey(%VK_CONTROL, 0), %KEYEVENTF_KEYUP, 0: Sleep 0 'key_UP msg
       If (iTempShifted And 4) Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), %KEYEVENTF_KEYUP, 0: Sleep 0       'key_UP msg
    End Sub
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Sub WaitForNoKeys    'you can use this function to wait until user lets go of the ctrl/Alt/Shift and any other keys
       Local KeyWasPressed  As Long
       Local iKey           As Long
       Do                'loop here until user lets go of the ctrl/Alt/Shift and any other keys
          Sleep 300
          KeyWasPressed = 0
          For iKey = 19 To 255         '0-9 and a-z
             If (GetAsyncKeyState(iKey) And 1) Then KeyWasPressed = 1
          Next iKey
          If (GetAsyncKeyState(%VK_CONTROL) And &H8000) Or (GetAsyncKeyState(%VK_SHIFT) And &H8000) Or (GetAsyncKeyState(%VK_MENU) And &H8000) Then KeyWasPressed = 1  'note: VK_MENU = VK_ALT
       Loop While KeyWasPressed
    End Sub
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Function AppActivate(ByVal sWinName As String) As Long  'Switches focus to the named window using undocumented SwitchToThisWindow function
       Local zWinName    As Asciiz * %MAX_PATH
       Local hUser32     As Dword
       Local dProcAddr   As Dword
       Local iRet        As Long
       Local hFindDlg    As Long
       zWinName = sWinName
       hFindDlg = FindWindow(ByVal 0, zWinName)  'find window by name
       If hFindDlg = 0 Then Exit Function        'cant find window so exit
       hUser32 = GetModuleHandle("user32.dll")   'get handle for DLL already in mem
       If hUser32 = 0 Then Exit Function         'cant find dll so exit
       dProcAddr = GetProcAddress(hUser32, "SwitchToThisWindow")         'get subroutine address from dll
       If dProcAddr = 0 Then Exit Function       'cant find sub in dll
       Call Dword dProcAddr Using SwitchToWin(hFindDlg, %TRUE) To iRet   'call routine
       Function = iRet                           'return results (1=success 0=failed)
    End Function
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    Sub SendPlainText(ByVal sText As String)
       Local iRet           As Long
       Local iCounter       As Long
       Local iVKcode        As Integer
       Local iTempShifted   As Long
       For iCounter = 1 To Len(sText)
          iRet = VkKeyScan(Asc(sText,iCounter))
          If (LoByt(iRet) = -1) And (HiByt(iRet) = -1) Then Iterate For 'cant do this char so skip
          iVKcode = LoByt(iRet)
          iTempShifted = HiByt(iRet)
          If (iTempShifted And 1) Then keybd_event %VK_SHIFT, MapVirtualKey(%VK_SHIFT, 0), 0, 0: Sleep 0     'hold down shift
          If (iTempShifted And 2) Then keybd_event %VK_CONTROL, MapVirtualKey(%VK_CONTROL, 0), 0, 0: Sleep 0 'hold down control
          If (iTempShifted And 4) Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), 0, 0: Sleep 0      'hold down alt
          keybd_event iVKcode, MapVirtualKey(iVKcode, 0), 0, 0: Sleep 0                'key_down msg
          keybd_event iVKcode, MapVirtualKey(iVKcode, 0), %KEYEVENTF_KEYUP, 0: Sleep 0 'key_up msg
          If (iTempShifted And 1) Then keybd_event %VK_SHIFT, MapVirtualKey(%VK_SHIFT, 0), %KEYEVENTF_KEYUP, 0: Sleep 0     'key_up msg
          If (iTempShifted And 2) Then keybd_event %VK_CONTROL, MapVirtualKey(%VK_CONTROL, 0), %KEYEVENTF_KEYUP, 0: Sleep 0 'key_up msg
          If (iTempShifted And 4) Then keybd_event %VK_MENU, MapVirtualKey(%VK_MENU, 0), %KEYEVENTF_KEYUP, 0: Sleep 0       'key_up msg
       Next iCounter
    End Sub
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    ------------------
    "I haven't lost my mind... its backed up on tape... I think??"



    [This message has been edited by William Burns (edited March 23, 2004).]
    "I haven't lost my mind... its backed up on tape... I think??" :D

  • #2
    Here is an example of using the above SendKeys include file.

    (It is also a simple example of using global hotkeys)

    Code:
    #COMPILE EXE      'Example program for SendKeys.Inc file
    #REGISTER NONE
    #DIM ALL
    #INCLUDE "SendKeys.Inc" '<-- file found in Source Code forum (above)  - by William Burns
    GLOBAL hDlg AS LONG
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    CALLBACK FUNCTION DlgProc
       STATIC nAtom() AS DWORD
       LOCAL sText    AS STRING
       LOCAL iRet     AS LONG
       LOCAL iCount   AS LONG
          SELECT CASE CBMSG
             CASE %WM_INITDIALOG
                iRet = TIMER
                REDIM nAtom(1:3)
                FOR iCount = 1 TO 3
                   nAtom(iCount) = GlobalAddAtom ("My Hotkeys" + STR$(iRet + iCount))  'make each unique
                   RegisterHotKey CBHNDL, nAtom(iCount), 2, 64 + iCount ' Ctrl-A-B-C
                NEXT iCOunt
             CASE %WM_DESTROY
                FOR iCount = 1 TO 3
                   UnregisterHotKey CBHNDL, nAtom(iCount)
                   GlobalDeleteAtom nAtom(iCount)
                NEXT iCount
             CASE %WM_HOTKEY
                SELECT CASE CBWPARAM
                   CASE nAtom(1) 'Ctrl-a
                      AppActivate "Untitled - Notepad"  'switch to notepad window (if found)
                      WaitForNoKeys 'use this to wait for user to let go of keys (so our keys dont end up as ctrl keys)
                      sText = "{4 + 4 = 8} It is now " & DATE$ & " " & LEFT$(TIME$,5)
                      SendPlainText sText
                   CASE nAtom(2) 'Ctrl-b
                      WaitForNoKeys  'use this to wait for user to let go of keys (so our keys dont end up as ctrl keys)
                      SendKeys "{AppActivate Untitled - Notepad}12{UP}34{END}567890" 'Switch to notepad then type 12 then go up and type 34 and go to end of line type 567890
                      SendKeys "{SLEEP 1000}{BACKSPACE}{SLEEP 500}" 'pause, backspace, pause
                      SendKeys "{BACKSPACE 3}"  'send 3 backspaces
                   CASE nAtom(3) 'Ctrl-c
                      sText = INPUTBOX$("Enter string to send" + $CRLF + $CRLF + "You'll have 3 seconds " _
                               + "to switch back to the program to send keystokes.","Send what?")
                      SLEEP 3000
                      SendKeys sText
                END SELECT
          END SELECT
    END FUNCTION
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    FUNCTION PBMAIN
       DIALOG NEW 0, "SendKeys example",,, 300, 30,%WS_MINIMIZEBOX OR %WS_SYSMENU OR %WS_CAPTION, 0 TO hDlg
       CONTROL ADD LABEL, hDlg, 205, "Switch to another program and then press Ctrl-A or Ctrl-B or Ctrl-C in to send keystrokes", 5, 10, 290, 15, %SS_CENTER
       DIALOG SHOW MODAL hDlg CALL DlgProc
    END FUNCTION
    '=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
    '  other hot-key examples:
    'RegisterHotKey CbHndl, nAtom, 0, Asc("D") ' D
    'RegisterHotKey CbHndl, nAtom, 1, Asc("D") ' Alt-D
    'RegisterHotKey CbHndl, nAtom, 2, Asc("D") ' Ctrl-D
    'RegisterHotKey CbHndl, nAtom, 4, Asc("D") ' Shift-D
    'RegisterHotKey CbHndl, nAtom, 1 + 2, Asc("D") ' Ctrl-Alt-D
    ------------------
    "I haven't lost my mind... its backed up on tape... I think??"

    [This message has been edited by William Burns (edited December 30, 2002).]
    "I haven't lost my mind... its backed up on tape... I think??" :D

    Comment


    • #3
      I am trying to send a CTRL END to a dialog Box so that I can go
      to the end of TEXTBOX.


      The Code Line is...
      SendKeys "{^}{END}"

      The Scroll bar elavator on the right side of the Window moves up and down.
      but it never goes to the Bottom of the TextBox. Always goes back to the top.

      I was able to use other sendkeys succesfully

      Any Sugestions would be helpful..




      ------------------
      mailto:[email protected][email protected]</A>
      mailto:[email protected][email protected]</A>

      Comment


      • #4
        Joseph: Use the %EM_SETSEL message.

        Please note that the source code forum is intended for p[osting code only. Questions and discussions (and even thank you messages to show appreciation for source code, etc) should be posted in a more appropriate forum.


        ------------------
        Lance
        PowerBASIC Support
        mailto:[email protected][email protected]</A>
        Lance
        mailto:[email protected]

        Comment


        • #5
          A tiny mistake in "SUB SendPlainText(BYVAL sText AS STRING)" with %VK_SHIFT:

          IF (iTempShifted AND 4) THEN KeyBd_Event %VK_MENU, MapVirtualKey(%VK_SHIFT, 0), 0, 0: SLEEP 0 'hold down alt

          Better:
          IF (iTempShifted AND 4) THEN KeyBd_Event %VK_MENU, MapVirtualKey %VK_MENU, 0), 0, 0: SLEEP 0 'hold down alt

          Ok?


          ------------------

          Comment


          • #6

            A few notes from a not overly bright first time user...


            Keep in mind that SendKeys is case sensitive
            Code:
            SendKeys "%f" ' ALT-f
            SendKeys "%F" ' ALT-SHIFT-f
            
            SendKeys "^f" ' CTRL-F
            SendKeys "^f" ' CTRL-SHIFT-F
            
            Sending Function keys like F9. 
            SendKeys "{F9}"  ' Function Key F9
            SendKeys "^{F9}" ' Ctrl-F9
            
            SendKeys "{ENTER}" ' Enter see the sendkeys.inc file
            SendKeys "{ESC}    ' Escape
            SendKeys "{TAB}"   ' Tab      
            
            
            To REGISTER other HotKeys with windows ....   
            RegisterHotKey CbHndl, nAtom, 0, Asc("D") ' D                    
            RegisterHotKey CbHndl, nAtom, 0, 68       ' D
            RegisterHotKey CbHndl, nAtom, 1, Asc("D") ' Alt-D
            RegisterHotKey CbHndl, nAtom, 2, Asc("D") ' Ctrl-D
            RegisterHotKey CbHndl, nAtom, 4, Asc("D") ' Shift-D
            RegisterHotKey CbHndl, nAtom, 1 + 2, Asc("D") ' Ctrl-Alt-D 
            
            RegisterHotKey CbHndl, nAtom, 0, 13       ' ENTER - dangerous
            
            RegisterHotKey CbHndl, nAtom, 0, ??? ' F9
            
                  
            Also, don't forget to process dialog events
            
                  FOR i = 1 TO 40  ' Erase suggested text entry in target app
                    DIALOG DOEVENTS
                    SendKeys "{BACKSPACE}" 
                  NEXT
                  SendPlainText Addrs(i).Street ' Insert my entry
                  
            If you need to wait while the app you are sending keys to is processing use
                  SendKeys "{SLEEP 3000}" \
                  
            
            I found that I could use the GetDesktopWindow()
            function to look for windows that shoudl appear when commands are issued
            or buttons hit. I also used it in a loop with a SLEEP to wait for a process
            to complete knowing that the process puts up a window called
            "Finding..." for example. I also want to use CTRL-C to copy the contents
            of a textbox to clipboard and then examine it to see if it contains
            results I am expecting.
            
            
            If the developers of the target app were nice enought to throw up a dialog while processing (might not allways have time to be drawn)
            then look for it. In my case the processing window was called "Finding..."
            
                  WHILE Finding  ' wait for dialog to complete 
                    DIALOG DOEVENTS 
                    SendKeys "{SLEEP 4000}" 
                  WEND    
            where:
            
            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
             FUNCTION GetChildText(Ihwnd AS LONG) AS STRING   
              DIM Textlen AS LONG
              DIM sTemp AS STRING
            
                ON ERROR RESUME NEXT
                Textlen = SendMessage(Ihwnd, %WM_GETTEXTLENGTH, 0, 0)
                IF Textlen = 0 THEN
                    FUNCTION = ""
                    EXIT FUNCTION
                END IF
                Textlen = Textlen + 1
                sTemp   = STRING$(Textlen,0)
                Textlen = SendMessage(Ihwnd, %WM_GETTEXT, Textlen, STRPTR(sTemp))
                FUNCTION = LEFT$(sTemp, Textlen)
            END FUNCTION
            
            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
            FUNCTION Finding() AS LONG 
            
              DIM hWndChild AS LONG   
              DIM xRes AS STRING  
              DIM hWndParent AS LONG  
                       
                hWndParent = GetDesktopWindow()
                hWndChild  = GetWindow(hWndParent, %GW_CHILD OR %GW_HWNDFIRST)
                DO WHILE hWndChild <> 0
                  xRes = GetChildText(hWndChild)
                  IF xRes <> "" THEN ' PRINT #hDbg, LEFT$(xRes, 80) 
                    IF INSTR( xRes, "Finding..." ) THEN
                      FUNCTION = 1 ' window is found
                      EXIT FUNCTION
                    END IF     
                  END IF
                  hWndChild = GetWindow(hWndChild, %GW_HWNDNEXT)
                LOOP  
            
            END FUNCTION 
            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
            
            
            similarly, if dont want to be stuck with untitled file ...
            sAppDocName = FindFileName() ' to be clear
            SendKeys "{AppActivate " + sAppDocName + "}" ' Use open file name 
            SendKeys "^f"     ' CTRL-F ' open the Find Address window
            
            
            where:
            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
            FUNCTION FindFileName() AS STRING ' find doc open in MapSource
            
              DIM hWndChild AS LONG   
              DIM xRes AS STRING  
              DIM hWndParent AS LONG  
            
                hWndParent = GetDesktopWindow()
                hWndChild = GetWindow(hWndParent, %GW_CHILD OR %GW_HWNDFIRST)
                DO WHILE hWndChild <> 0
                  xRes = GetChildText(hWndChild)
                  IF xRes <> "" THEN ' PRINT #hDbg, LEFT$(xRes, 80) 
                    IF INSTR( xRes, "- MapSource" ) THEN
                      FUNCTION = TRIM$( xRes ) 
                      EXIT FUNCTION
                    END IF     
                  END IF
                  hWndChild = GetWindow(hWndChild, %GW_HWNDNEXT)
                LOOP  
            
                MSGBOX "MapSource Not Found",64,"Error" ' quit the app
            
            END FUNCTION    
            
            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤


            ------------------
            Kind Regards
            Mike

            Comment


            • #7
              SendKeys has been superseded, but IF you are still using it and IF you need to send a mouseclick to a foreign app to UNSELCT what was selected, here's a small mod:

              In the SUB SendEachKey(), insert these 3 lines into the main CASE:

              Code:
                    case "{XMOUSECLICK}"              ' mouseclick to unselect text
                       CALL MouseClick(UCASE$(MID$(sChar,2,1)),0,0)
                       EXIT SUB
              I stuck it right before "{LMOUSECLICK}".

              -John

              Comment


              • #8
                Another tidbit for SendKeys...

                IF you need the other app to save a file, AND IF that location is across a LAN, you may hit timing delays, so you add something like a {SLEEP 500}, and probably, you're fine; the app finally resolves the path, and your command to save then executes.

                BUT: IF you're trying to feed a full path and filename to that app in one string, you may hit another problem - the other app gets lost and confused.
                So if {SLEEP xxx} didn't help, try this: break the path and filename into two separate commands.

                Change this:
                Code:
                SendKeys "P:\01 New\MyFile.txt{ENTER}"
                Into:
                Code:
                SendKeys "P:\01 New\{ENTER}"   ' Step 1: first, force the change of directory
                
                Sleep 200         'take a quick breather
                
                SendKeys "MyFile.txt{ENTER}"   ' Step2: now provide the filename
                -John

                Comment

                Working...
                X