Page 1 of 2

Clip() - Send and Retrieve Text using the Clipboard

Posted: 18 Feb 2019, 21:38
by berban
Clip() - Send and Retrieve Text using the Clipboard

V2 VERSION OF THIS FUNCTION HERE

This is an update to an old post in order to bring it to the new live version of the forums. The old post is here: https://autohotkey.com/board/topic/70404-clip-send-and-retrieve-text-using-the-clipboard/



Using the windows clipboard with AutoHotkey is useful, but it can be confusing and annoying. You'll probably want to backup and restore the contents so that the previous data isn't erased. Usually it also requires a few sleeps to work correctly. This script helps to standardize some of those uses in a small package.

This script includes two of the most common uses of 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.


Download code from Github: https://github.com/berban/Clip/blob/master/Clip.ahk



Clip(Text="", ReSelect=False)


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

Code: Select all

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.

Code: Select all

; The two are analogous. Use of the clipboard is generally preferable for larger amounts of text
Clip("Some text")
SendInput {Raw}Some text ; {Raw} avoids sending keyboard combinations like ^v as ctrl+v
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: (Optional parameter) 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()?
  • Has the right amount of sleep based on many years of experience to work reliably. (Because of trickiness using the windows clipboard, it still might fail to copy or paste every once in a while.)
  • 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:

Code: Select all

; Displays the selected text
MsgBox, % "The selected text is: " Clip()

; Sends "long text string" using ctrl-v
Clip("long text string")

; Sends "long text string" and then re-selects it
Clip("long text string", True)

; Puts quotes around the selected text.
; Despite calling Clip() twice, the clipboard is only backed up & restored once
Clip("""" Clip() """")
More involved examples: (from 2011, use at your own risk!)

Code: Select all

; 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
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.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 18 Feb 2019, 22:13
by TAC109
Interesting..
BTW, the link to the old post at the beginning doesn’t seem to work.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 18 Feb 2019, 23:31
by berban
TAC109 wrote:
18 Feb 2019, 22:13
BTW, the link to the old post at the beginning doesn’t seem to work.
Thanks for catching that! Updated.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 19 Feb 2019, 12:16
by burque505
@berban, thanks very much. All examples are working fine on Win7 64-bit, AHK_L 1.1.30.01 64-bit.
Regards,
burque505

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 23 Feb 2019, 00:36
by 0x00
Neat, i personally use these though, a bit more intuitive dare i say... Get(), Put(), to take care of most use cases & to get Selected or All Text Left/Right of caret...

Code: Select all

MsgBox % Get()
MsgBox % Get("L")
MsgBox % Get("R")
MsgBox % Get("L") "`n`n" Get("R",false)
Put("Hello World")


Put(string){		;as an alternative to send,to instantly place a string
	ClipSaved := ClipboardAll, clipboard := "", clipboard := string
	clipwait
	BlockInput, on
	Send ^v
	BlockInput, off
	Clipboard := ClipSaved
}


Get(whichSideOfCaret:="",deselect:=true){		;gets everything to left or right of cursor	---> set param to 'L' or 'R', blank param gets selection...
	ClipSaved := ClipboardAll, clipboard := ""
	BlockInput, on
	( whichSideOfCaret = "R" ? Send("{Shift down}{end}{Shift up}{Ctrl down}{c}{Ctrl up}") & (deselect?Send("{Left}")) : (whichSideOfCaret = "L" ? Send("{Shift down}{home}{Shift up}{Ctrl down}{c}{Ctrl up}") & (deselect?Send("{Right}"):"") : (!whichSideOfCaret ? Send("{Ctrl down}{c}{Ctrl up}") : "")) )
	BlockInput, off
	clipwait, 1
	string := clipboard, Clipboard := ClipSaved
	Return string
}


Send(keys){
	Send % keys
}


Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 26 Aug 2019, 18:14
by GollyJer
Hi. I just wanted to say thank you! 🎉
I've been using Clip for 10 years and it's always been reliable. Love it! 😍

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 01 Oct 2019, 08:36
by someguyinKC
how can I use this method of scripting but also get the ending character to come through. by ending character, I'm referring to the character that triggers the script, often it is a space, but sometimes it is a period or a quote or a dash, etc.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 01 Oct 2019, 13:53
by boiler
someguyinKC wrote:
01 Oct 2019, 08:36
how can I use this method of scripting but also get the ending character to come through. by ending character, I'm referring to the character that triggers the script, often it is a space, but sometimes it is a period or a quote or a dash, etc.
I just noticed that you also asked this question in the other thread where you were asking about your larger issue. It's difficult for people to answer here because your question doesn't mean anything in the context of this thread. They would need to know that what you are calling a script is really a hotstring definition within a script. And they would need to know how you're using this function in conjunction with your hotstrings.

To answer your question, you would accomplish that like this:

Code: Select all

:X:a::Clip("aaaaaaaaaaaaaaaaaaaaa" . A_EndChar)

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 01 Oct 2019, 14:04
by burque505
Thanks, boiler, that's a good tip.
Regards,
burque505

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 02 Oct 2019, 09:55
by berban
Hey someguyinKC,

Sorry I didn't get a notification for some reason. But boiler is correct, that is how you would do it. (In fact I didn't know about the "X" option for hotstrings so I am glad they posted!)

Let me know if you have any further questions.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 03 Oct 2019, 11:38
by someguyinKC
boiler:

in your example:

Code: Select all

:X:a::Clip("aaaaaaaaaaaaaaaaaaaaa" . A_EndChar)
what is that X for?

thanks,

someguy

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 03 Oct 2019, 12:07
by boiler
It specifies the Hotstring option to execute the text that follows as a command rather than send it as literal text.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 02 Mar 2020, 04:33
by aellie
This script cured my acne.

In all seriousness—and for future Googlers, if any—I've been using hotstrings to send emoji, and it works in almost every program, but not in Scrivener for some reason. Honestly at this point I barely care why. The important thing is, using this script to send them fixed the problem, and I'm happy about it.

Thank you so much.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 12 Mar 2021, 23:33
by iPhilip
Hi @berban,

Thank you for your Clip() function. I wanted to share a hotkey/function combination that makes it easy for me to switch between Upper, Lower or Title formats for a selected string. It uses your ReSelect parameter. :)

Code: Select all

F3::Clip(Format("{:" GetNextCaseFormat() "}", Clip()), true)

GetNextCaseFormat() {
   static i := 0, Formats := ["U", "L", "T"]
   return Formats[++i > 3 ? i := 1 : i]
}
Cheers!

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 13 Mar 2021, 04:26
by ozzii
@iPhilip
I can't make it work.
Can you give me a more detailed example please?

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 13 Mar 2021, 11:53
by iPhilip
ozzii wrote:
13 Mar 2021, 04:26
@iPhilip
I can't make it work.
Can you give me a more detailed example please?
@ozzii,
Thank you for reaching out for help. The first thing I want to make sure that you did was to include the Clip() function. If you have it saved in a file named Clip.ahk in the same folder as the example code I posted you can simply use the #Include directive as follows:

Code: Select all

#Include Clip.ahk

F3::Clip(Format("{:" GetNextCaseFormat() "}", Clip()), true)

GetNextCaseFormat() {
   static i := 0, Formats := ["U", "L", "T"]
   return Formats[++i > 3 ? i := 1 : i]
}
Otherwise, below is a fully-self contained version that you can download and run:

Code: Select all

F3::Clip(Format("{:" GetNextCaseFormat() "}", Clip()), true)

GetNextCaseFormat() {
   static i := 0, Formats := ["U", "L", "T"]
   return Formats[++i > 3 ? i := 1 : i]
}

; Clip() - Send and Retrieve Text Using the Clipboard
; by berban - updated February 18, 2019
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=62156
Clip(Text="", Reselect="")
{
	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 and ((ReSelect = True) or (StrLen(Text) < 3000))
			SendInput, % "{Shift Down}{Left " StrLen(StrReplace(Text, "`r")) "}{Shift Up}"
	}
	Return
	Clip:
	Return Clip()
}
After you run the script, you should be able to select one or more words, press the F3 key repeatedly, and see the word change from Upper to Lower to Title formats. For example, if you selected the word AutoHotkey, it would sequentially change to AUTOHOTKEY, autohotkey, Autohotkey, AUTOHOTKEY, etc.

Please let me know how this works out for you.

- iPhilip

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 14 Mar 2021, 10:48
by ozzii
Thank you @iPhilip
I don't know why the first time it didn't work.
Thank you again, this can be useful.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 31 Aug 2021, 19:30
by chaoscreater
How can I get rid of the copied text in the clipboard history? I just want to use this to paste the text into the field, but not actually retain any text in the clip history.

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 09 Sep 2021, 20:30
by berban
I’m not aware of any way to easily do that with autohotkey, not with the default commands at least. You might have to dive into dllcalls to either use an alternate copy/paste or to change the clipboard history. Sorry about that!

Re: Clip() - Send and Retrieve Text using the Clipboard

Posted: 08 Nov 2021, 01:28
by guest3456
berban wrote:
18 Feb 2019, 21:38
Download code from Github: https://github.com/berban/Clip/blob/master/Clip.ahk
how does this ternary work?

ClipWait, LongCopy ? 0.6 : 0.2, True

isnt LongCopy always going to be non-zero and therefore the timeout will always be 0.6 ?


another question:

why do you set a timer to re-call the func in order to restore the old clipboard, instead of just restoring it yourself in the same func call?