<br>(*<br>SendKeys routine for 32-bit Delphi.<br><br>Written by Ken Henderson<br><br>Copyright (c) 1995 Ken Henderson<br><br>This unit includes two routines that simulate popular Visual Basic<br>routines: Sendkeys and AppActivate. SendKeys takes a PChar<br>as its first parameter and a boolean as its second, like so:<br><br>SendKeys('KeyString', Wait);<br><br>where KeyString is a string of key names and modifiers that you want<br>to send to the current input focus and Wait is a boolean variable or value<br>that indicates whether SendKeys should wait for each key message to be<br>processed before proceeding. See the table below for more information.<br><br><br>SendKeys supports the Visual Basic SendKeys syntax, as documented below.<br><br>Supported modifiers:<br><br>+ = Shift<br>^ = Control<br>% = Alt<br><br>Surround sequences of characters or key names with parentheses in order to<br>modify them as a group. For example, '+abc' shifts only 'a', while '+(abc)' shifts<br>all three characters.<br><br>Supported special characters<br><br>~ = Enter<br>( = Begin modifier group (see above)<br>) = End modifier group (see above)<br>{ = Begin key name text (see below)<br>} = End key name text (see below)<br><br>Supported characters:<br><br>Any character that can be typed is supported. Surround the modifier keys<br>listed above with braces in order to send as normal text.<br><br>Supported key names (surround these with braces):<br><br>BKSP, BS, BACKSPACE<br>BREAK<br>CAPSLOCK<br>CLEAR<br>DEL<br>DELETE<br>DOWN<br>END<br>ENTER<br>ESC<br>ESCAPE<br>F1<br>F2<br>F3<br>F4<br>F5<br>F6<br>F7<br>F8<br>F9<br>F10<br>F11<br>F12<br>F13<br>F14<br>F15<br>F16<br>HELP<br>HOME<br>INS<br>LEFT<br>NUMLOCK<br>PGDN<br>PGUP<br>PRTSC<br>RIGHT<br>SCROLLLOCK<br>TAB<br>UP<br><br>Follow the keyname with a space and a number to send the specified key a<br>given number of times (e.g., {left 6}).<br>*)<br><br>unit qbsndkey32;<br><br>interface<br><br>Uses SysUtils, Windows, Messages;<br><br>Function SendKeys(SendKeysString : PChar) : Boolean;<br><br>{Buffer for working with PChar's}<br><br>const<br> WorkBufLen = 40;<br>var<br> WorkBuf : array[0..WorkBufLen] of Char;<br><br>implementation<br>type<br> THKeys = array[0..pred(MaxLongInt)] of byte;<br>var<br> AllocationSize : integer;<br><br>(*<br>Converts a string of characters and key names to keyboard events and<br>passes them to Windows.<br><br>Example syntax:<br><br>SendKeys('abc123{left}{left}{left}def{end}456{left 6}ghi{end}789', True);<br><br>*)<br><br>Function SendKeys(SendKeysString : PChar) : Boolean;<br>type<br> WBytes = array[0..pred(SizeOf(Word))] of Byte;<br><br> TSendKey = record<br> Name : ShortString;<br> VKey : Byte;<br> end;<br><br>const<br> {Array of keys that SendKeys recognizes.<br><br> If you add to this list, you must be sure to keep it sorted alphabetically<br> by Name because a binary search routine is used to scan it.}<br><br> MaxSendKeyRecs = 41;<br> SendKeyRecs : array[1..MaxSendKeyRecs] of TSendKey =<br> (<br> (Name:'BACKSPACE'; VKey:VK_BACK),<br> (Name:'BKSP'; VKey:VK_BACK),<br> (Name:'BREAK'; VKey:VK_CANCEL),<br> (Name:'BS'; VKey:VK_BACK),<br> (Name:'CAPSLOCK'; VKey:VK_CAPITAL),<br> (Name:'CLEAR'; VKey:VK_CLEAR),<br> (Name:'DEL'; VKey:VK_DELETE),<br> (Name:'DELETE'; VKey:VK_DELETE),<br> (Name:'DOWN'; VKey:VK_DOWN),<br> (Name:'END'; VKey:VK_END),<br> (Name:'ENTER'; VKey:VK_RETURN),<br> (Name:'ESC'; VKey:VK_ESCAPE),<br> (Name:'ESCAPE'; VKey:VK_ESCAPE),<br> (Name:'F1'; VKey:VK_F1),<br> (Name:'F10'; VKey:VK_F10),<br> (Name:'F11'; VKey:VK_F11),<br> (Name:'F12'; VKey:VK_F12),<br> (Name:'F13'; VKey:VK_F13),<br> (Name:'F14'; VKey:VK_F14),<br> (Name:'F15'; VKey:VK_F15),<br> (Name:'F16'; VKey:VK_F16),<br> (Name:'F2'; VKey:VK_F2),<br> (Name:'F3'; VKey:VK_F3),<br> (Name:'F4'; VKey:VK_F4),<br> (Name:'F5'; VKey:VK_F5),<br> (Name:'F6'; VKey:VK_F6),<br> (Name:'F7'; VKey:VK_F7),<br> (Name:'F8'; VKey:VK_F8),<br> (Name:'F9'; VKey:VK_F9),<br> (Name:'HELP'; VKey:VK_HELP),<br> (Name:'HOME'; VKey:VK_HOME),<br> (Name:'INS'; VKey:VK_INSERT),<br> (Name:'LEFT'; VKey:VK_LEFT),<br> (Name:'NUMLOCK'; VKey:VK_NUMLOCK),<br> (Name:'PGDN'; VKey:VK_NEXT),<br> (Name:'PGUP'; VKey:VK_PRIOR),<br> (Name:'PRTSC'; VKey:VK_PRINT),<br> (Name:'RIGHT'; VKey:VK_RIGHT),<br> (Name:'SCROLLLOCK'; VKey:VK_SCROLL),<br> (Name:'TAB'; VKey:VK_TAB),<br> (Name:'UP'; VKey:VK_UP)<br> );<br><br> {Extra VK constants missing from Delphi's Windows API interface}<br> VK_NULL=0;<br> VK_SemiColon=186;<br> VK_Equal=187;<br> VK_Comma=188;<br> VK_Minus=189;<br> VK_Period=190;<br> VK_Slash=191;<br> VK_BackQuote=192;<br> VK_LeftBracket=219;<br> VK_BackSlash=220;<br> VK_RightBracket=221;<br> VK_Quote=222;<br> VK_Last=VK_Quote;<br><br> ExtendedVKeys : set of byte =<br> [VK_Up,<br> VK_Down,<br> VK_Left,<br> VK_Right,<br> VK_Home,<br> VK_End,<br> VK_Prior, {PgUp}<br> VK_Next, {PgDn}<br> VK_Insert,<br> VK_Delete];<br><br>const<br> INVALIDKEY = $FFFF {Unsigned -1};<br> VKKEYSCANSHIFTON = $01;<br> VKKEYSCANCTRLON = $02;<br> VKKEYSCANALTON = $04;<br> UNITNAME = 'SendKeys';<br>var<br> UsingParens, ShiftDown, ControlDown, AltDown, FoundClose : Boolean;<br> PosSpace : Byte;<br> I, L : Integer;<br> NumTimes, MKey : Word;<br> KeyString : String[20];<br><br>procedure DisplayMessage(Message : PChar);<br>begin<br> MessageBox(0,Message,UNITNAME,0);<br>end;<br><br>function BitSet(BitTable, BitMask : Byte) : Boolean;<br>begin<br> Result:=ByteBool(BitTable and BitMask);<br>end;<br><br>procedure SetBit(var BitTable : Byte; BitMask : Byte);<br>begin<br> BitTable:=BitTable or Bitmask;<br>end;<br><br>Procedure KeyboardEvent(VKey, ScanCode : Byte; Flags : Longint);<br>var<br> KeyboardMsg : TMsg;<br>begin<br> keybd_event(VKey, ScanCode, Flags,0);<br> //If (Wait) then While (PeekMessage(KeyboardMsg,0,WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) do begin<br> //If (Wait) then<br> While (PeekMessage(KeyboardMsg,0,WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) do<br> begin<br> TranslateMessage(KeyboardMsg);<br> DispatchMessage(KeyboardMsg);<br> end;<br>end;<br><br>Procedure SendKeyDown(VKey: Byte; NumTimes : Word; GenUpMsg : Boolean);<br>var<br> Cnt : Word;<br> ScanCode : Byte;<br> NumState : Boolean;<br> KeyBoardState : TKeyboardState;<br>begin<br> If (VKey=VK_NUMLOCK) then begin<br> NumState:=ByteBool(GetKeyState(VK_NUMLOCK) and 1);<br> GetKeyBoardState(KeyBoardState);<br> If NumState then KeyBoardState[VK_NUMLOCK]:=(KeyBoardState[VK_NUMLOCK] and not 1)<br> else KeyBoardState[VK_NUMLOCK]:=(KeyBoardState[VK_NUMLOCK] or 1);<br> SetKeyBoardState(KeyBoardState);<br> exit;<br> end;<br><br> ScanCode:=Lo(MapVirtualKey(VKey,0));<br> For Cnt:=1 to NumTimes do<br> If (VKey in ExtendedVKeys)then begin<br> KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY);<br> If (GenUpMsg) then<br> KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)<br> end else begin<br> KeyboardEvent(VKey, ScanCode, 0);<br> If (GenUpMsg) then KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);<br> end;<br>end;<br><br>Procedure SendKeyUp(VKey: Byte);<br>var<br> ScanCode : Byte;<br>begin<br> ScanCode:=Lo(MapVirtualKey(VKey,0));<br> If (VKey in ExtendedVKeys)then<br> KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY and KEYEVENTF_KEYUP)<br> else KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);<br>end;<br><br>Procedure SendKey(MKey: Word; NumTimes : Word; GenDownMsg : Boolean);<br>begin<br> If (BitSet(Hi(MKey),VKKEYSCANSHIFTON)) then SendKeyDown(VK_SHIFT,1,False);<br> If (BitSet(Hi(MKey),VKKEYSCANCTRLON)) then SendKeyDown(VK_CONTROL,1,False);<br> If (BitSet(Hi(MKey),VKKEYSCANALTON)) then SendKeyDown(VK_MENU,1,False);<br> SendKeyDown(Lo(MKey), NumTimes, GenDownMsg);<br> If (BitSet(Hi(MKey),VKKEYSCANSHIFTON)) then SendKeyUp(VK_SHIFT);<br> If (BitSet(Hi(MKey),VKKEYSCANCTRLON)) then SendKeyUp(VK_CONTROL);<br> If (BitSet(Hi(MKey),VKKEYSCANALTON)) then SendKeyUp(VK_MENU);<br>end;<br><br>{Implements a simple binary search to locate special key name strings}<br><br>Function StringToVKey(KeyString : ShortString) : Word;<br>var<br> Found, Collided : Boolean;<br> Bottom, Top, Middle : Byte;<br>begin<br> Result:=INVALIDKEY;<br> Bottom:=1;<br> Top:=MaxSendKeyRecs;<br> Found:=false;<br> Middle:=(Bottom+Top) div 2;<br> Repeat<br> Collided:=((Bottom=Middle) or (Top=Middle));<br> If (KeyString=SendKeyRecs[Middle].Name) then begin<br> Found:=True;<br> Result:=SendKeyRecs[Middle].VKey;<br> end else begin<br> If (KeyString>SendKeyRecs[Middle].Name) then Bottom:=Middle<br> else Top:=Middle;<br> Middle:=(Succ(Bottom+Top)) div 2;<br> end;<br> Until (Found or Collided);<br> If (Result=INVALIDKEY) then DisplayMessage('Invalid Key Name');<br>end;<br><br>procedure PopUpShiftKeys;<br>begin<br> If (not UsingParens) then begin<br> If ShiftDown then SendKeyUp(VK_SHIFT);<br> If ControlDown then SendKeyUp(VK_CONTROL);<br> If AltDown then SendKeyUp(VK_MENU);<br> ShiftDown:=false;<br> ControlDown:=false;<br> AltDown:=false;<br> end;<br>end;<br><br>begin<br> AllocationSize:=MaxInt;<br> Result:=false;<br> UsingParens:=false;<br> ShiftDown:=false;<br> ControlDown:=false;<br> AltDown:=false;<br> I:=0;<br> L:=StrLen(SendKeysString);<br> If (L>AllocationSize) then L:=AllocationSize;<br> If (L=0) then Exit;<br><br> While (I<L) do begin<br> case SendKeysString of<br> '(' : begin<br> UsingParens:=True;<br> Inc(I);<br> end;<br> ')' : begin<br> UsingParens:=False;<br> PopUpShiftKeys;<br> Inc(I);<br> end;<br> '%' : begin<br> AltDown:=True;<br> SendKeyDown(VK_MENU,1,False);<br> Inc(I);<br> end;<br> '+' : begin<br> ShiftDown:=True;<br> SendKeyDown(VK_SHIFT,1,False);<br> Inc(I);<br> end;<br> '^' : begin<br> ControlDown:=True;<br> SendKeyDown(VK_CONTROL,1,False);<br> Inc(I);<br> end;<br> '{' : begin<br> NumTimes:=1;<br> If (SendKeysString[Succ(I)]='{') then begin<br> MKey:=VK_LEFTBRACKET;<br> SetBit(Wbytes(MKey)[1],VKKEYSCANSHIFTON);<br> SendKey(MKey,1,True);<br> PopUpShiftKeys;<br> Inc(I,3);<br> Continue;<br> end;<br> KeyString:='';<br> FoundClose:=False;<br> While (I<=L) do begin<br> Inc(I);<br> If (SendKeysString='}') then begin<br> FoundClose:=True;<br> Inc(I);<br> Break;<br> end;<br> KeyString:=KeyString+Upcase(SendKeysString);<br> end;<br> If (Not FoundClose) then begin<br> DisplayMessage('No Close');<br> Exit;<br> end;<br> If (SendKeysString='}') then begin<br> MKey:=VK_RIGHTBRACKET;<br> SetBit(Wbytes(MKey)[1],VKKEYSCANSHIFTON);<br> SendKey(MKey,1,True);<br> PopUpShiftKeys;<br> Inc(I);<br> Continue;<br> end;<br> PosSpace:=Pos(' ',KeyString);<br> If (PosSpace<>0) then begin<br> NumTimes:=StrToInt(Copy(KeyString,Succ(PosSpace),Length(KeyString)-PosSpace));<br> KeyString:=Copy(KeyString,1,Pred(PosSpace));<br> end;<br> If (Length(KeyString)=1) then MKey:=vkKeyScan(KeyString[1])<br> else MKey:=StringToVKey(KeyString);<br> If (MKey<>INVALIDKEY) then begin<br> SendKey(MKey,NumTimes,True);<br> PopUpShiftKeys;<br> Continue;<br> end;<br> end;<br> '~' : begin<br> SendKeyDown(VK_RETURN,1,True);<br> PopUpShiftKeys;<br> Inc(I);<br> end;<br> else begin<br> MKey:=vkKeyScan(SendKeysString);<br> If (MKey<>INVALIDKEY) then begin<br> SendKey(MKey,1,True);<br> PopUpShiftKeys;<br> end else DisplayMessage('Invalid KeyName');<br> Inc(I);<br> end;<br> end;<br> end;<br> Result:=true;<br> PopUpShiftKeys;<br>end;<br><br>end.<br>