Catch copy/paste of empty text on Windows from AutoHotKey script
By default on Windows, when copying text, it gets put in the clipboard. But when attempting to copy empty text, the clipboard is untouched. For example, selecting no text in your editor, then hitting ctrl+c
, will cause no change in the clipboard.
Problem is, I need to catch this event with AutoHotKey. Since the clipboard is unchanged, I have no idea how to do this开发者_C百科 cleanly (without a timeout, that is).
Does anyone have any idea how to do this?
Edit: To clarify, I'm sending the ctrl+c from within AutoHotKey. I'm doing so to tell if any text is selected, i.e., I'm sending ctrl+c, then checking if any text was copied to the clipboard or not. Problem is, if no text is selected, the clipboard handlers for AutoHotKey never get called, forcing me to use a timeout, which isn't good practice.
Here is what I did. Since the clipboard is a variable in AutoHotkey, you can check to see if it is empty. I first cleared the clipboard, send control+c, then see if the clipboard is still empty. You can temporarily move the current clipboard to a temporary place first if you want.
ClipSaved := ClipboardAll
Clipboard = ; empties the clipboard
Send ^+{Left} ; I just used highlight left to select text, you can replace this with
; whatever your program uses to select an input.
Send ^c ; attempt to copy text
If Clipboard = ; checks to see if clipboard is empty
{
break ; Put what you want to do if the clipboard is empty, I used break to stop a loop
}
Clipboard := ClipSaved ; puts the original clipboard contents back
I was searching text from an open document in which the user can choose a forward or backward direction. When going backwards, it would get stuck in a loop at the beginning of the document. I set a loop limit to keep it from being an infinite loop, but it still wasted time having to wait for the loop to finish. I used the break function to end the loop if the clipboard was empty.
To give credit where credit is due, I got the inspiration from another post which had other tood tips. It posted you can check for a blank variable with this script. http://www.autohotkey.net/~deleyd/xprxmp/autohotkey_expression_examples.htm#J v := ""
If v =
MsgBox v = ""
If (v = "")
MsgBox v = ""
From the AutoHotkey documentation website I found out how to temporarily store and replace the clipboard content. http://www.autohotkey.com/docs/misc/Clipboard.htm
ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
;... here make temporary use of the clipboard, such as for pasting Unicode text via Transform Unicode ...
Clipboard := ClipSaved ; Restore the original clipboard. Note the use of Clipboard (not ClipboardAll).
ClipSaved = ; Free the memory in case the clipboard was very large.
Hope this helps. Samuel
Here's the solution I currently use. Basically, it comes down to sending ctrl+c
, waiting a certain timeout, then seeing if text was actually copied. If it wasn't, I know there is not selection.
There is no way, afaik, to avoid waiting a timeout, since Windows takes a certain time to perform the copy
operation. I set the timeout to 0.15 seconds, so it isn't too bad.
Here's the function I use whenever I want to grab the contents of the clipboard, or check if it's empty. I always call this function first:
clipped_text :=
clip_empty := false
ClipSaved =
is_clipped := false
clip_speed := 0.15
Clip() {
global ClipSaved
global clip_empty
global clipped_text
global is_clipped
global clip_speed
if (!is_clipped) {
ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
; msgbox % ClipSaved
is_clipped := true
}
clipboard = ; Empty the clipboard
Send ^{c}
ClipWait clip_speed
if (ErrorLevel = 1)
{
clip_empty := false
}
else
{
clip_empty := true
clipped_text := clipboard
}
}
And I use this function to actually get the contents of the clipboard or check if it's empty:
IsTextSelected() {
global ClipSaved
global clip_empty
global clipped_text
if (clip_empty == true) {
return true
}
else {
return false
}
}
To get the contents of the clipboard I just look at the clipped_text variable.
After performing a "Clip()" operation, I always call the following function to restore the clipboard (this function is called once for multiple calls of Clip()
):
UnClip() {
global ClipSaved
global clip_empty
global clipped_text
global is_clipped
is_clipped := false
Clipboard := ClipSaved
ClipSaved =
}
While not an actual answer to this question, a google search might lead you here if you are looking for a way to catch text on paste and modify it before pasting.
Here's the script which eliminates whitespace from text pasted from clipboard on CTRL + V:
~^v::
Trimmed := RegExReplace(Clipboard, "^\s+", "")
Trimmed := RegExReplace(Trimmed, "\s+$", "")
Clipboard = %Trimmed%
SendInput ^v
return
I think I have a solution. Set aside current clipboard, then copy. Compare what you have copied to an empty string.. if it's equal, then something was copied; otherwise, nothing was copied. At then, restore the clipboard to what you saved. Here is a code sample demonstrating the principle.
^#x::
ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
; ... here make temporary use of the clipboard, such as for pasting Unicode text via Transform Unicode ...
Clipboard := ; Clear the clipboard
Send, {CTRLDOWN}c{CTRLUP}
if (Clipboard = "") {
Send, you copied nothing
} else {
Send, you copied something
}
Clipboard := ClipSaved ; Restore the original clipboard. Note the use of Clipboard (not ClipboardAll).
ClipSaved = ; Free the memory in case the clipboard was very large.
return
Actually, I was hoping that there is another way to simply test if the cursor is currently selecting anything. I have asked this question on the AutoHotkey forums (http://www.autohotkey.com/forum/posting.php?mode=reply&t=69468), but until or if there is a better answer, I will use the above method.
Script for babylon (Middle Mouse Key for firefox):
MButton::
SetTitleMatchMode, 2
send {LButton}{LButton}
Send ^c
sleep, 100
send {F10}
sleep, 100
SendInput {Raw}%clipboard%
send {enter}
Return
I had the same problem - I would send the copy command, but it wouldn't copy anything. I tried working with timers to no avail.
Here is what I ended up doing (trying different modes):
thisclipboard := clipboard . a_now ;add NOW so that it won't possibly be the same as the contents of the clipboard
sendplay,^c
if(clipboard == thisclipboard){
sendinput,^c
}
if(clipboard == thisclipboard){
send,^c
}
Maybe you should hotkey the Ctrl + C instead, that way any time that hotkey is pressed you will know.
You might want to make sure to send the normal Ctrl + C action to windows so you can copy. consider this example:
~^c::
msgbox, % "Clipboard Changed even if you didnt copy anything"
. "(...not really but you tried at least)"
return
That message will fire up every time you press Ctrl + C even if you didnt copy anything to the clipboard. At the same time you will be sending the native function of Ctrl + C to windows so your clipboard WILL change if you copied something.
From the help file:
~: When the hotkey fires, its key's native function will not be blocked (hidden from the system).
You might want to also have an onClipboardChange
to check when the clipboard really changed.
精彩评论