Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

listen to clipboard changes, check ownership?

Tags:

java

clipboard

I want to be notified if a string is copied to the system clipboard. When a new string is copied from the same source application, the FlavorListener won't get an event. To get informed when another string is copied, i read the string from the clipboard, convert it to a SrtingSelection, which is able to take the ownership, and put it back to the clipboard. Now I got informed twice, once the StringSelection lost ownership and once it takes it back. Is there a way to check for the ownership directly, instead of storing the string and check it equals the new one? Here is my code so far:

 import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws Exception {
        // The clipboard
        final Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
        // read clipboard and take ownership to get the FlavorListener notified
        // when the content has changed but the owner has not
        processClipboard(cb);
        cb.addFlavorListener(new FlavorListener() {
            @Override
            public void flavorsChanged(FlavorEvent e) {
                processClipboard(cb);
            }
        });
        // keep thread for testing
        Thread.sleep(100000L);
    }

    public static void processClipboard(Clipboard cb) {
        // gets the content of clipboard
        Transferable trans = cb.getContents(null);
        if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
            try {
                // cast to string
                String s = (String) trans
                        .getTransferData(DataFlavor.stringFlavor);
                System.out.println(s);
                // only StringSelection can take ownership, i think
                StringSelection ss = new StringSelection(s);
                // set content, take ownership
                cb.setContents(ss, ss);
            } catch (UnsupportedFlavorException e2) {
                e2.printStackTrace();
            } catch (IOException e2) {
                e2.printStackTrace();
            }
        }
    }
}

I hope you understand my bad english :-(

like image 428
anonymous001 Avatar asked Mar 30 '11 10:03

anonymous001


2 Answers

The previous answer is close to be working.

The real cure is to instead just monitor the event of ownership change. By the monitor's occupying the clipboard as owner when monitoring the clipboard, so when any application changes the clipboard, the ownership would change, so this would reliably indicate the clipboard content change. However, this approach must have sufficient wait to work, (200 ms was found to be working) after an ownership change event before accessing the clipboard and re-occupying the clipboard.

This solution was provided and proved to be working by marc weber at http://www.coderanch.com/t/377833/java/java/listen-clipboard

I have verified for my purpose. If needed, I can post the solution here.

Yu

like image 144
2 revs Avatar answered Sep 23 '22 16:09

2 revs


To avoid double notification remove the flavor listener before setting the new clipboard content and add the listener again after setting clipboard content.

public class NewClass implements FlavorListener, ClipboardOwner{
    private Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();  
    public NewClass() {
        System.out.println("NewClass constructor");
        clip.setContents(clip.getContents(null), this);
        clip.addFlavorListener(this);
        try {
            Thread.sleep(100000L);
        }
        catch (InterruptedException e) {

        }
    }

    @Override
    public void flavorsChanged(FlavorEvent e) {
        System.out.println("ClipBoard Changed!!!");
        clip.removeFlavorListener(this);
        clip.setContents(clip.getContents(null), this);
        clip.addFlavorListener(this);

    }

    @Override
    public void lostOwnership(Clipboard arg0, Transferable arg1) {
        System.out.println("ownership losted");
    }
}
like image 36
AdrZ Avatar answered Sep 23 '22 16:09

AdrZ