0
votes

I'm trying to have 2 clipboards (or more), with an ahk script.

Desired behaviour is working with the standard ^v plus !v so it will be 2 clipboards. ^v being the usual one, !v will be the previous content that ^v had.

If I copy 'text1' on clipboard, I will have this as ^v. If I copy 'text2' I will have 'text2' on clipboard with ^v, plus the old 'text1' available with !v, and so on.

This is so far:

lastclip = %clipboard%

!v::
                global lastclip
                sendclip(lastclip)
return

ClipWaitChange()

ClipWaitChange()
{
  While changed=0 {
    global lastclip
    lastclip = %clipboard%
    Sleep 10
  }
  OnClipboardChange:
    changed = 1
    return
}

But it returns a blank clipboard or maybe ^v stops working.

Any hints how to do that?

sendclip is just a custom func to send the clipboard contents by keyboard

I tried put lastclip = %clipboard% inside onclipboardchange but it copies the current changed clipboard, so has to be done before that.

1
A few things are unclear to me: 1) Where's the closing brace for While changed=0 { ? 2) Why create a waiting loop in the first place if you already have the handy "event" OnClipboardChange? 3) You're talking about ^v which is CTRL+v. In your code, you defined !v which is ALT+v. Which hotkey(s) are we talking about? Please describe exactly what you want to happen upon which event or user action and how you want to write to and read from 2 clipboards separately.MCL
I thought i needed the while to be constantly checking / pasting the current clipboard. I'm updating the descriptionCristo

1 Answers

1
votes

I assume your question is of an academic nature. If not, I recommend one of the many Clipboard Managers already out there.

Here's a solution with comments:

lastClip := ""
bufferedClip := Clipboard

OnClipboardChange("clipChangeHandler")

; Note that the ALT key can change focus, better use WIN+V
#v::
    ; Since we temporarily switch Clipboard's contents,
    ; we want to ignore the event it will fire
    OnClipboardChange("clipChangeHandler", 0)
    ; I recommend pasting rather than sending
    tmpClip := Clipboard
    Clipboard := lastClip
    Send, ^v
    Clipboard := tmpClip
    tmpClip := ""
    OnClipboardChange("clipChangeHandler")
return

clipChangeHandler(evtInfo) {
    global lastClip, bufferedClip
    ; Check if Clipboard contains actual text
    if(evtInfo  = 1) {
        lastClip := bufferedClip
        bufferedClip := Clipboard
    }
}

See also OnClipboardChange in AHK docs.

A few remarks:

  • The event function checks for the event type being (partially) real text, ignoring pure non-text like images and also empty clipboards
  • clipBuffer always stores the current clipboard and lastClip contains the previous clipboard. You need the buffer variable, since the event doesn't offer something like a previous clipboard
  • ALT + v can be problematic when working with windows that have a classic menu bar. Hitting ALT (even before releasing it) will often switch focus away from the current control.
  • I recommend pasting rather than sending. E.g. when there's large text in the clipboard with thousands of words (maybe even put there by another program or simply by mistake), sending each character one by one can take a long time or may even come with other side effects. If you want to Send regardless, at least use SendRaw so that certain characters won't be mistreated as control sequences (e.g. sending #e will open Windows Explorer).
  • Always consider security aspects of your application. If you (our your password safe e.g.) empty your clipboard to delete sensitive data, your script will still keep an (unencrypted) copy of it, for every other process to see.