Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Clip() - Send and Retrieve Text using the Clipboard


  • Please log in to reply
15 replies to this topic
berban
  • Members
  • 202 posts
  • Last active: Apr 12 2019 01:08 AM
  • Joined: 30 Dec 2009
New forum link: https://www.autohotk...php?f=6&t=62156
Use that thread if you have questions as this one is archived.

Clip() - All your clipboard needs in one place


This script consolidates two things you do that involve the clipboard: Finding out what text is currently being selected, and sending large amounts of text via Control+V. It also standardizes some features often needed with these operations, and improves performance through consolidation.

Clip(Text="", ReSelect=False)

Usage: Call it without any parameters to retrieve the text currently selected.


Var := Clip() ; will store any selected text in %Var%
Or call it with some text in the first parameter to "send" that text via the clipboard and Control+V.


; The two are analogous. Clip() is generally preferable for larger amounts of text
Clip("Some text")
SendInput {Raw}Some text ; Raw because when using Clip() keyboard combinations like ^s (ctrl+s) will be sent literally. SendInput {Raw} also does this.
Parameters:
  • Text:If you put text in this parameter, the function will send the text via the clipboard. If you leave this parameter blank, the function will return the selected text instead.
  • ReSelect: Only use this parameter in send mode (i.e. if there is text in the first parameter.) If ReSelect is true (has a value of 1), the cursor will re-select the just-pasted text. This is convenient if you are going to make extra modifications to the text, for instance, if you want to bold it after you paste it. If ReSelect is empty or false (equal to 0), then it will not reselect the text. If ReSelect is any other value (such as 2 or a non-numeric string), it will only reselect the text if there are 3000 or fewer characters - more than this number may be lead to choppy re-selecting.
Why use Clip()?
  • Can send and retrieve with one function
  • No delay while sending. Normally you have to wait 400ms or so after sending Control+V before restoring the clipboard's contents, or else sometimes it pastes the backup contents instead. Clip() tasks this to a timer so your script can continue executing.
  • Improves performance by only saving & restoring the clipboard's contents once in the case of rapid clipboard operations.
  • Can reselct pasted text.
Some working examples:


;----------------------------------------------------------------------------------------------------
; Simple examples

^1::MsgBox, % "The selected text is: " Clip() ; displays the selected text
^2::Clip(A_Now, True) ; sends A_Now and then re-selects it
^3::Clip("""" Clip() """") ; puts quotes around the selected text. Despite calling Clip() twice, the clipboard is only backed up & restored once



;----------------------------------------------------------------------------------------------------
; More involved example
; The below hotkeys add some of the features of SciTE to notepad.

#IfWinActive ahk_class Notepad ; makes the hotkeys context-sensitive

; Duplicate the above line
^d::
	SendInput {End}+{Home}
	@ := Clip()
	SendInput {End}{Enter}
	Clip(@)
	Return

; Swap with the above line
^t::
	SendInput {End}+{Home}
	@ := Clip()
	SendInput {Del 2}{Up}{Enter}{Up}
	Clip(@)
	Return

; Indent a block of text. (This introduces a small delay for typing a normal tab; to avoid this you can use ^Tab / ^+Tab as a hotkey instead.)
$Tab::
$+Tab::
	TabChar := A_Tab ; this could be something else, say, 4 spaces
	NewLine := "`r`n"
	If ("" <> Text := Clip()) {
		@ := ""
		Loop, Parse, Text, `n, `r
			@ .= NewLine (InStr(A_ThisHotkey, "+") ? SubStr(A_LoopField, (InStr(A_LoopField, TabChar) = 1) * StrLen(TabChar) + 1) : TabChar A_LoopField)
		Clip(SubStr(@, StrLen(NewLine) + 1), 2)
	} Else
		Send % (InStr(A_ThisHotkey, "+") ? "+" : "") "{Tab}"
	Return

#IfWinActive
Code:


Clip(Text="", Reselect="") ; http://www.autohotkey.com/forum/viewtopic.php?p=467710 , modified February 19, 2013
{
	Static BackUpClip, Stored, LastClip
	If (A_ThisLabel = A_ThisFunc) {
		If (Clipboard == LastClip)
			Clipboard := BackUpClip
		BackUpClip := LastClip := Stored := ""
	} Else {
		If !Stored {
			Stored := True
			BackUpClip := ClipboardAll ; ClipboardAll must be on its own line
		} Else
			SetTimer, %A_ThisFunc%, Off
		LongCopy := A_TickCount, Clipboard := "", LongCopy -= A_TickCount ; LongCopy gauges the amount of time it takes to empty the clipboard which can predict how long the subsequent clipwait will need
		If (Text = "") {
			SendInput, ^c
			ClipWait, LongCopy ? 0.6 : 0.2, True
		} Else {
			Clipboard := LastClip := Text
			ClipWait, 10
			SendInput, ^v
		}
		SetTimer, %A_ThisFunc%, -700
		Sleep 20 ; Short sleep in case Clip() is followed by more keystrokes such as {Enter}
		If (Text = "")
			Return LastClip := Clipboard
		Else If (ReSelect = True) or (Reselect and (StrLen(Text) < 3000)) {
			StringReplace, Text, Text, `r, , All
			SendInput, % "{Shift Down}{Left " StrLen(Text) "}{Shift Up}"
		}
	}
	Return
	Clip:
	Return Clip()
}
Notes:
  • With any large amount of text (more than 20 or so characters), it is usually MUCH faster to send it via the clipboard, as opposed to with Send or SendInput.
  • Clip() waits only .15 seconds before its ClipWait times out and reports that no text is selected. I have done some testing and decided that this is an ample amount. However, on a slow machine it is possible you might have to increase this timeout.
  • The delayed restoration of the clipboard that occurs with Clip() can have unintended consequences. For instance, if you send some text with Clip() and then immediately exit the script, the clipboard will never be restored to its original state because the timer to restore it did not expire.
  • You cannot have another "Clip" label in your script. If this is problematic, you can easily enough change the name of the label.

Find me on the new AutoHotkey forums and send me a message if you have a question about any of the scrips I've posted to this forum!


  • Guests
  • Last active:
  • Joined: --
Useful snippet!
Related for those interested:
[function] Virtual clipboards+ by Learning one
<!-- m -->http://www.autohotke...topic56926.html<!-- m -->

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
Used in AHKLink

closed
  • Members
  • 509 posts
  • Last active: Jan 14 2012 06:14 PM
  • Joined: 07 Feb 2008
Thanks Berban! very useful and big improvement to ^v :)

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011
Genius!

Thank you so much for posting this. If only I'd found this when you'd first posted it. The general process of 1. backing up the clipboard, 2. SendInput ^v, 3. Sleep from 35 to 150+ by much trial and error, 4. and finally restoring the clipboard has been the bane of my AHK experience. If only "SendInput % var" were as fast and as accurate as "SendInput ^v," or effectively operated as your Clip(), then this inefficient, faulty process would be unnecessary.

In my initial testing, the SetTimer period of -700 seems far too high (i.e. low. ;), making it counterproductive to restoring the clipboard quickly; -50 seems to work for me just fine.

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011
Thanks ParticleMan!

Actually the long delay is somewhat intentional. This leaves you 700 milliseconds for additional calls of Clip(). Say you're populating fields in a website:
Clip("first name")
Send {Tab} ; go to next field
Clip("last name")
Send {Tab}
Clip("123 fake street")
Send {Tab}
Clip("Springfield")
; etc ...
Each time Clip() is used, it bumps the clipboard restoring back another 700 milliseconds. So throughout the whole process the clipboard will only be restored once, at the end. This is more efficient, especially because working with the windows clipboard is very cpu-intensive. Storing data in the clipboard takes about 90x longer than storing data in a regular AutoHotkey variable - so it should be done judiciously.

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011
Indeed, a long delay is desirable for populating website fields, but a short delay is desirable for key repeating; otherwise, the wrong clipboard data can be sent. So, unfortunately, it depends on the use.

I've been upgrading my scripts to use Clip() and the results have been great! However, I have instances just as in your example where additional sleep is needed after tabbing. It seems that a quick succession of pastes is the most problematic. What can be improved? I can't claim to understand your magic as yet.

Now, I'd also like to see this implemented into WinClip (<!-- l --><a class="postlink-local" href="http://www.autohotkey.com/community/viewtopic.php?t=79998">viewtopic.php?t=79998</a><!-- l -->). Simply replacing its paste with Clip(Clipboard) doesn't work.

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011
What do you mean by "key repeating"? You may be misunderstanding how the function works (well indeed you admit that yourself.)

Pretty much the only situation where a delay would be problematic would be a situation like the one I have at the end of the first post, where you use Clip() and then exit immediately after. The only other situation would be if you are almost simultaneously interacting with the clipboard and using Clip(). For instance if you use Clip() to send some text and then immediately (in under 7/10ths of a second) manage to select some new text and press ctrl+c, then Clip() could overwrite your new contents with the clipboard backup. But this is difficult to say the least and not very useful. I've only had issues with the script exiting part.

Regarding WinClip, I haven't heard of it but it looks intriguing. It's probably a good cut above Clip() in terms of its capabilities though. If you want to merge them I would instead recommend putting WinClip into Clip(), not the other way around.
First though, I always like to ask what the end goal is. What specifically do you like about WinClip (or Clip() for that matter), and why do you want to combine them? How would you be using it ultimately? For which tasks?

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011
"Key repeating" as in pressing a hotkey repeatedly. I use macros that manipulate text more than that tab around and paste different strings on webpages. As in automation tools, I would rather fill out webpages with JavaScript but through AHK, and if this is possible, I don't know to do it effectively.

So far, I use WinClip() only for its HTML pasting, such that a variable containing HTML will paste formatted, as well as for pasting syntax-highlighted text.

Ultimately, I want to paste any kind of data, whether copied to one of my custom persistent, multiple clipboards or from a variable, with the reliability of the native Windows clipboard.

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011
The longer delay would also be beneficial in the scenario you describe. In fact it would allow for faster repeating of the hotkey, because restoring the clipboard each repeat takes extra time. 50 milliseconds might be long enough to achieve this but I would bump it up to at least 150ms or so to be safe.

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011
Maybe in theory, but my mileage varies. In my experience, shorter is better both for hotkey repetition and for tabbing-pasting. Sometimes a delay of 150 works where 200 or more does not. However, other times more than 700 seems to help, particularly on webpages, because of unpredictable system lags. I just don't see Clip() working as designed, due to whatever reason.

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011
I think I have a solution to the timer delay issue. In short, that's not the issue.

What's needed is a sleep of at least 6 ms after the Send ^v, at least on the two boxes I've tried it on thus far. With that addition, a quick succession of multiple calls to Clip(var), with small or large amounts of data, will paste properly and not send incorrect or no data and at all as well as not fail to buffer hotkey presses.

It may not matter which sleep is used, whether asynchronous Sleep or synchronous dllcall("Sleep", Uint, delay), but I've been having better experience with synchronous sleep in my testing.

I've also found no reason to use ClipWait after a Clipboard := var. ClipWait seems useful only when it is guaranteed that data will be copied (which is why I never use ClipWait, since many times it's possible to copy null).

formivore
  • Members
  • 4 posts
  • Last active: Feb 16 2013 12:44 AM
  • Joined: 29 Oct 2012
Wow, this looks great! I will have to try it out.

There's so much you can do with AHK by manipulating the clipboard. But doing this has has always been so clunky...

faqbot
  • Members
  • 997 posts
  • Last active:
  • Joined: 10 Apr 2012
I add this as newbies seem to have troube understanding how to use is the OP post is too complicated as it assumes you know ahk which many don't - faqbot recommended clip() so many times faqbot is tired of explaining it again and again

Clip() Instructions for newbies

Step 1: Copy the code from the first post, it is marked CODE at the end of the post and starts with Clip(Text="", Reselect="")

Step 2: Save this code in a new file called clip.ahk

Now you can do two things, you can either use #Include see http://www.autohotke...ds/_Include.htm or you place clip.ahk in your LIB folder see http://www.autohotke...nctions.htm#lib

Step 3: Using Clip()

Simple hotstring example
;#include Clip.ahk ; uncomment this line if you haven't placed clip.ahk in your LIB folder

::btw::
Clip("This is some text I want to paste")
Return

Using a (multiline-)variable

;#include Clip.ahk ; uncomment this line if you haven't placed clip.ahk in your LIB folder

::btw::
var=
(join`r`n
This is
some text
I want to paste

OK
)
Clip(var)
Return

Other example with various variables http://www.autohotke...ns/#entry545901

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011

Just curious, but what is the purpose of the LongCopy variable?

LongCopy := A_TickCount, Clipboard := "", LongCopy -= A_TickCount
  If (Text = "") {
   Send, ^c
   ClipWait, LongCopy ? 0.5 : 0.25
  } Else {
   Clipboard := LastClip := Text
   ClipWait, 10
   Send, ^v
  }

What does the length of time it takes to clear the clipboard have to do with that amount of time to wait when storing something to the clipboard?

 

I replaced that section of code with

If (Text = "") {
    Clipboard := ""
    Send, ^c
    ClipWait, 0.5
} 
Else {
    Clipboard := LastClip := Text
    ClipWait, 10
    Send, ^v
}

and it seems to function the same as your OP, or am I missing something?


My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!