SendKeys Procedure

Share your advanced PureBasic knowledge/code with the community.
ebs
Enthusiast
Enthusiast
Posts: 530
Joined: Fri Apr 25, 2003 11:08 pm

SendKeys Procedure

Post by ebs »

Here is a procedure similar to Visual Basic's SendKeys(). It will send a specified string to the foreground application as if the keys had been pressed on the keyboard. It should work for all ASCII characters, including those that don't have a #VK_xxx constant value, like punctuation characters.

Code: Select all

; send the specified key
Procedure SendKey(Key.s)
  ; get virtual key code and shift state
  VK.w = VkKeyScan_(Asc(Key))
  If VK = -1
    ProcedureReturn
  EndIf
  
  ; get scan code if an extended key
  If MapVirtualKey_(VK, 2) = 0
    Extended.l = #KEYEVENTF_EXTENDEDKEY
    ; get scan code
    Scan.l = MapVirtualKey_(VK, 0)
  Else
    Extended = 0 
    Scan = 0
  EndIf
  
  ; press shift/ctrl/alt if needed
  Shift.l = VK & $100
  Ctrl.l = VK & $200
  Alt.l = VK & $400
  If Shift
    keybd_event_(#VK_SHIFT, 0, 0, 0)
  EndIf
  If Ctrl
    keybd_event_(#VK_CONTROL, 0, 0, 0)
  EndIf
  If Alt
    keybd_event_(#VK_MENU, 0, 0, 0)
  EndIf
  
  ; press and release key
  VK & $ff
  keybd_event_(VK, Scan, Extended, 0)
  keybd_event_(VK, Scan, #KEYEVENTF_KEYUP | Extended, 0)
  
  ; release shift/ctrl/alt if pressed
  If Shift
    keybd_event_(#VK_SHIFT, 0, #KEYEVENTF_KEYUP, 0)
  EndIf
  If Ctrl
    keybd_event_(#VK_CONTROL, 0, #KEYEVENTF_KEYUP, 0)
  EndIf
  If Alt
    keybd_event_(#VK_MENU, 0, #KEYEVENTF_KEYUP, 0)
  EndIf
EndProcedure

; send string to foreground application  
Procedure SendKeys(String.s)
  For Letter.l = 1 To Len(String)
    SendKey(Mid(String, Letter, 1))
  Next
EndProcedure

; test
For n.l = 1 To 10
  Delay(2000)
  SendKeys("Hello There!" + Chr(13))
Next
To test the code, open any text editor. Start the program and quickly switch back to the text editor. You should see the 10 lines of text.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: SendKeys Procedure

Post by PB »

Nice code, ebs -- much shorter than my earlier tip. My tip also allows
sending of keys like F1, Pause, PageUp, and so on. Check it out:

viewtopic.php?t=3766
ebs
Enthusiast
Enthusiast
Posts: 530
Joined: Fri Apr 25, 2003 11:08 pm

Post by ebs »

My tip also allows sending of keys like F1, Pause, PageUp, and so on.
That was going to be my next step! :D
Now I can just "borrow" your code.

Thanks for your help,
Eric
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

Great Code - because it works with ALL characters (german umlauts and such funny stuff)! :)

BUT...
...does anyone know to disable the real keyboard while sending these infos?

I would need this, because it could happen, that the user will press a key while a string will be sent out and this can lead to unwanted effects

For example, holding down the shift-key will show something like "HeLLO TherE!" instead of "Hello There!" :cry:

Michael
marroh
User
User
Posts: 72
Joined: Wed Aug 06, 2008 8:21 am

Post by marroh »

Code: Select all

BlockInput_(#True)
...
...
...
BlockInput_(#False)
NT-Systems only, as i know.
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

marroh wrote:

Code: Select all

BlockInput_(#True)
 :
BlockInput_(#False)
NT-Systems only, as i know.
Thanks, marroh - I checked it using Windows XP...

(+) 'shift' and 'caps lock' seems to be blocked/ignored here :D
(–) 'alt' is not blocked :cry:
(–) 'ctrl' is not blocked :cry:

Michael
dioxin
User
User
Posts: 97
Joined: Thu May 11, 2006 9:53 pm

Post by dioxin »

For multiple keys use SendInput:

http://msdn.microsoft.com/en-us/library ... S.85).aspx
The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput.
marcos.exe
User
User
Posts: 20
Joined: Fri Jan 17, 2020 8:20 pm

Re: SendKeys Procedure

Post by marcos.exe »

Hi!
I don't know if only I missed it, or I didn't use it properly!

The right and left cursor arrows do not work.
The right and left that is in place is the numeric keypad.
Is it possible to make the arrows work normally?

NOTE: My windows are in Brazilian Portuguese, as well as my keyboard. I don't know if this has anything to do with it!

Translated by google.
When our generation/OS updates, we either update ourselves, or we are removed.
But we are never fully uninstalled.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: SendKeys Procedure

Post by Kwai chang caine »

I use this short and nice code of EBS for sending string 8)
http://www.purebasic.fr/english/viewtop ... 1486#31486

Code: Select all

Procedure SendKeys(String.s)
  
 For Letter.l = 1 To Len(String)
  
  Delay(10)
  Key.s = Mid(String, Letter, 1)
  
  ; get virtual key code and shift state 
  VK.w = VkKeyScan_(Asc(Key))
  
  If VK = -1 
   ProcedureReturn 
  EndIf 
  
  ; get scan code if an extended key 
  If MapVirtualKey_(VK, 2) = 0 
   Extended.l = #KEYEVENTF_EXTENDEDKEY 
   ; get scan code 
   Scan.l = MapVirtualKey_(VK, 0) 
  Else 
   Extended = 0 
   Scan = 0 
  EndIf 
  
  ; press shift/ctrl/alt if needed 
  Shift.l = VK & $100 
  Ctrl.l = VK & $200 
  Alt.l = VK & $400
  
  If Shift 
   keybd_event_(#VK_SHIFT, 0, 0, 0) 
  EndIf
  
  If Ctrl 
   keybd_event_(#VK_CONTROL, 0, 0, 0) 
  EndIf
  
  If Alt 
   keybd_event_(#VK_MENU, 0, 0, 0) 
  EndIf 
  
  ; press and release key 
  VK & $ff 
  keybd_event_(VK, Scan, Extended, 0) 
  keybd_event_(VK, Scan, #KEYEVENTF_KEYUP | Extended, 0)
  Delay(10)
  
  ; release shift/ctrl/alt if pressed 
  If Shift 
   keybd_event_(#VK_SHIFT, 0, #KEYEVENTF_KEYUP, 0) 
  EndIf
  
  If Ctrl 
   keybd_event_(#VK_CONTROL, 0, #KEYEVENTF_KEYUP, 0) 
  EndIf
  
  If Alt 
   keybd_event_(#VK_MENU, 0, #KEYEVENTF_KEYUP, 0) 
  EndIf
  
 Next
 
EndProcedure
But i see the "~" character is not writing :shock:
After searching, I believe have found the problem :oops:
The MapVirtualKey_() return zero then that VK = 1586 :shock:
VK.w = VkKeyScan_(Asc("~"))
Debug MapVirtualKey_(VK, 0)
Someone know why ?
Have a good day
ImageThe happiness is a road...
Not a destination
User avatar
idle
Always Here
Always Here
Posts: 5038
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: SendKeys Procedure

Post by idle »

run this without debugger

Code: Select all

#INPUT_KEYBOARD = 1
#KEYEVENTF_UNICODE = 4 
#KEYEVENTF_KEYUP = 2 

Global Dim InputData.INPUT(0)

Procedure SendKeyInput(key.s)
  
  Protected *p.unicode   
    
  ReDim InputData.INPUT(((Len(key)*2)-1))
  
  *p = @key 
  While *p\u <> 0 
    InputData(a)\type = #INPUT_KEYBOARD
    InputData(a)\ki\wScan = *p\u  
    InputData(a)\ki\dwFlags = #KEYEVENTF_UNICODE
    a+1
    InputData(a)\type = #INPUT_KEYBOARD
    InputData(a)\ki\wScan = *p\u  
    InputData(a)\ki\dwFlags = #KEYEVENTF_UNICODE | #KEYEVENTF_KEYUP;
    a+1 
    *p+2 
  Wend   
  
  BlockInput_(1)
  aret = SendInput_(a,@inputdata(0),SizeOf(INPUT))
  BlockInput_(0) 
  If aret  
    Debug aret  
  EndIf    
    
EndProcedure  

GetForegroundWindow_() 
key.s = "Hello~!@#$%^&*()" 
sendkeyInput(key)

;put cursor here 

Quin
Enthusiast
Enthusiast
Posts: 279
Joined: Thu Mar 31, 2022 7:03 pm
Location: United States
Contact:

Re: SendKeys Procedure

Post by Quin »

Just tested, and this works flawlessly, thanks loads!
idle wrote: Wed Jan 10, 2024 9:19 pm run this without debugger

Code: Select all

#INPUT_KEYBOARD = 1
#KEYEVENTF_UNICODE = 4 
#KEYEVENTF_KEYUP = 2 

Global Dim InputData.INPUT(0)

Procedure SendKeyInput(key.s)
  
  Protected *p.unicode   
    
  ReDim InputData.INPUT(((Len(key)*2)-1))
  
  *p = @key 
  While *p\u <> 0 
    InputData(a)\type = #INPUT_KEYBOARD
    InputData(a)\ki\wScan = *p\u  
    InputData(a)\ki\dwFlags = #KEYEVENTF_UNICODE
    a+1
    InputData(a)\type = #INPUT_KEYBOARD
    InputData(a)\ki\wScan = *p\u  
    InputData(a)\ki\dwFlags = #KEYEVENTF_UNICODE | #KEYEVENTF_KEYUP;
    a+1 
    *p+2 
  Wend   
  
  BlockInput_(1)
  aret = SendInput_(a,@inputdata(0),SizeOf(INPUT))
  BlockInput_(0) 
  If aret  
    Debug aret  
  EndIf    
    
EndProcedure  

GetForegroundWindow_() 
key.s = "Hello~!@#$%^&*()" 
sendkeyInput(key)

;put cursor here 

PB v5.40/6.10, Windows 10 64-bit.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: SendKeys Procedure

Post by Kwai chang caine »

Hello my friend IDLE :D

Little.... powerfull.... best working...In one word (very difficult to do for KCC :mrgreen:)

PERFECT !!!!!

I have replacing the EBS procedure by yours immediately in my program :wink:
Thanks a lot and have a very good day 8)
Your fan
KCC
ImageThe happiness is a road...
Not a destination
Post Reply