Port code over from MyClipboardHistory
parent
59877150d0
commit
204020954c
@ -0,0 +1,42 @@
|
|||||||
|
package me.goudham;
|
||||||
|
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.datatransfer.Clipboard;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import me.goudham.listener.ClipboardEventListener;
|
||||||
|
|
||||||
|
abstract class ClipboardListener {
|
||||||
|
final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||||
|
List<ClipboardEventListener> eventsListener = new ArrayList<>();
|
||||||
|
private boolean imagesMonitored = true;
|
||||||
|
private boolean textMonitored = true;
|
||||||
|
|
||||||
|
void addEventListener(ClipboardEventListener clipboardEventListener) {
|
||||||
|
if (!eventsListener.contains(clipboardEventListener)) {
|
||||||
|
eventsListener.add(clipboardEventListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeEventListener(ClipboardEventListener clipboardEventListener) {
|
||||||
|
eventsListener.remove(clipboardEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isImagesMonitored() {
|
||||||
|
return imagesMonitored;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setImagesMonitored(boolean imagesMonitored) {
|
||||||
|
this.imagesMonitored = imagesMonitored;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTextMonitored() {
|
||||||
|
return textMonitored;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTextMonitored(boolean textMonitored) {
|
||||||
|
this.textMonitored = textMonitored;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void execute();
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package me.goudham;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.datatransfer.Clipboard;
|
||||||
|
import java.awt.datatransfer.Transferable;
|
||||||
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import me.goudham.domain.MyClipboardContent;
|
||||||
|
|
||||||
|
import static me.goudham.domain.Contents.IMAGE;
|
||||||
|
import static me.goudham.domain.Contents.STRING;
|
||||||
|
|
||||||
|
class ClipboardUtils {
|
||||||
|
|
||||||
|
static MyClipboardContent<?> getClipboardContents(Transferable contents, Clipboard clipboard) {
|
||||||
|
MyClipboardContent<?> myClipboardContent = new MyClipboardContent<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (STRING.isAvailable(clipboard)) {
|
||||||
|
myClipboardContent.setOldContent(contents.getTransferData(STRING.getDataFlavor()));
|
||||||
|
} else if (IMAGE.isAvailable(clipboard)) {
|
||||||
|
BufferedImage bufferedImage = convertToBufferedImage((Image) contents.getTransferData(IMAGE.getDataFlavor()));
|
||||||
|
myClipboardContent.setOldContent(new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight()));
|
||||||
|
}
|
||||||
|
} catch (UnsupportedFlavorException | IOException exp) {
|
||||||
|
exp.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return myClipboardContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BufferedImage convertToBufferedImage(Image image) {
|
||||||
|
BufferedImage newImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
Graphics2D graphics = newImage.createGraphics();
|
||||||
|
graphics.drawImage(image, 0, 0, null);
|
||||||
|
graphics.dispose();
|
||||||
|
|
||||||
|
return newImage;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package me.goudham;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.datatransfer.Transferable;
|
||||||
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import me.goudham.listener.ClipboardEventListener;
|
||||||
|
import me.goudham.domain.MyClipboardContent;
|
||||||
|
|
||||||
|
import static me.goudham.domain.Contents.IMAGE;
|
||||||
|
import static me.goudham.domain.Contents.STRING;
|
||||||
|
|
||||||
|
class MacClipboardListener extends ClipboardListener {
|
||||||
|
|
||||||
|
MacClipboardListener() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
Transferable oldClipboardContents = clipboard.getContents(null);
|
||||||
|
final MyClipboardContent<?>[] myClipboardContents = new MyClipboardContent[]{ ClipboardUtils.getClipboardContents(oldClipboardContents, clipboard) };
|
||||||
|
|
||||||
|
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
executor.scheduleAtFixedRate(() -> {
|
||||||
|
Transferable newClipboardContents = clipboard.getContents(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isTextMonitored()) {
|
||||||
|
if (STRING.isAvailable(clipboard)) {
|
||||||
|
String newContent = (String) newClipboardContents.getTransferData(STRING.getDataFlavor());
|
||||||
|
if (!newContent.equals(myClipboardContents[0].getOldContent())) {
|
||||||
|
for (ClipboardEventListener clipboardEventListener : eventsListener) {
|
||||||
|
clipboardEventListener.onCopyString(newContent);
|
||||||
|
}
|
||||||
|
myClipboardContents[0].setOldContent(newContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isImagesMonitored()) {
|
||||||
|
if (IMAGE.isAvailable(clipboard)) {
|
||||||
|
BufferedImage bufferedImage = ClipboardUtils.convertToBufferedImage((Image) newClipboardContents.getTransferData(IMAGE.getDataFlavor()));
|
||||||
|
Dimension newContent = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
|
||||||
|
if (!newContent.equals(myClipboardContents[0].getOldContent())) {
|
||||||
|
for (ClipboardEventListener clipboardEventListener : eventsListener) {
|
||||||
|
clipboardEventListener.onCopyImage(bufferedImage);
|
||||||
|
}
|
||||||
|
myClipboardContents[0].setOldContent(newContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (UnsupportedFlavorException | IOException exp) {
|
||||||
|
exp.printStackTrace();
|
||||||
|
}
|
||||||
|
}, 0, 350, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package me.goudham;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import me.goudham.exception.UnsupportedSystemException;
|
||||||
|
import me.goudham.listener.ClipboardEventListener;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) throws UnsupportedSystemException {
|
||||||
|
MyClipboard myClipboard = MyClipboard.getSystemClipboard();
|
||||||
|
myClipboard.addEventListener(new ClipboardEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onCopyString(String stringContent) {
|
||||||
|
System.out.println(stringContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCopyImage(BufferedImage imageContent) {
|
||||||
|
System.out.println(imageContent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//
|
||||||
|
// while (true) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// JClipboard jClipboard = JClipboard.getDefault();
|
||||||
|
// jClipboard.addEventListener(new JClipboardEventListener() {
|
||||||
|
// @Override
|
||||||
|
// public void onClipboardTextChange(JClipboardEvent event) {
|
||||||
|
// System.out.println("Was: " + event.getOldValue()); // The old value
|
||||||
|
// System.out.println("Is: " + event.getNewValue()); // The new value
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package me.goudham;
|
||||||
|
|
||||||
|
import me.goudham.exception.UnsupportedSystemException;
|
||||||
|
import me.goudham.listener.ClipboardEventListener;
|
||||||
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry Class for User to interact with the System Clipboard
|
||||||
|
*
|
||||||
|
* The abstract class {@link ClipboardListener} is responsible for handling all operations
|
||||||
|
*/
|
||||||
|
public class MyClipboard {
|
||||||
|
private final @NotNull ClipboardListener clipboardListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link MyClipboard}
|
||||||
|
*
|
||||||
|
* @param clipboardListener The underlying {@link ClipboardListener}
|
||||||
|
*/
|
||||||
|
private MyClipboard(@NotNull ClipboardListener clipboardListener) {
|
||||||
|
this.clipboardListener = clipboardListener;
|
||||||
|
this.clipboardListener.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link MyClipboard} with an instance of {@link ClipboardListener} dependant on the OS
|
||||||
|
* <p>A {@link WindowsOrUnixClipboardListener} or {@link MacClipboardListener} can be created</p>
|
||||||
|
*
|
||||||
|
* @return {@link MyClipboard}
|
||||||
|
* @throws UnsupportedSystemException If {@link MyClipboard} detects an operating system which is not Mac or Windows/*Unix
|
||||||
|
*/
|
||||||
|
public static MyClipboard getSystemClipboard() throws UnsupportedSystemException {
|
||||||
|
ClipboardListener clipboardListener;
|
||||||
|
|
||||||
|
if (isMac()) {
|
||||||
|
clipboardListener = new MacClipboardListener();
|
||||||
|
} else if (isWindows() || isUnix()) {
|
||||||
|
clipboardListener = new WindowsOrUnixClipboardListener();
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedSystemException("Your Operating System: " + System.getProperty("os.name") + "is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MyClipboard(clipboardListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an {@link ClipboardEventListener} to the underlying {@link ClipboardListener}
|
||||||
|
*
|
||||||
|
* @param clipboardEventListener The {@link ClipboardEventListener} to be added
|
||||||
|
*/
|
||||||
|
public void addEventListener(ClipboardEventListener clipboardEventListener) {
|
||||||
|
clipboardListener.addEventListener(clipboardEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMac() {
|
||||||
|
return SystemUtils.IS_OS_MAC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isUnix() {
|
||||||
|
return SystemUtils.IS_OS_UNIX || SystemUtils.IS_OS_LINUX;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isWindows() {
|
||||||
|
return SystemUtils.IS_OS_WINDOWS;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package me.goudham;
|
||||||
|
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.datatransfer.Clipboard;
|
||||||
|
import java.awt.datatransfer.ClipboardOwner;
|
||||||
|
import java.awt.datatransfer.DataFlavor;
|
||||||
|
import java.awt.datatransfer.Transferable;
|
||||||
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import me.goudham.listener.ClipboardEventListener;
|
||||||
|
|
||||||
|
import static java.lang.Thread.currentThread;
|
||||||
|
import static java.lang.Thread.sleep;
|
||||||
|
import static me.goudham.domain.Contents.IMAGE;
|
||||||
|
import static me.goudham.domain.Contents.STRING;
|
||||||
|
|
||||||
|
class WindowsOrUnixClipboardListener extends ClipboardListener implements Runnable, ClipboardOwner {
|
||||||
|
|
||||||
|
WindowsOrUnixClipboardListener() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lostOwnership(Clipboard oldClipboard, Transferable oldClipboardContents) {
|
||||||
|
try {
|
||||||
|
sleep(200);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Transferable newClipboardContents = oldClipboard.getContents(currentThread());
|
||||||
|
processContents(oldClipboard, newClipboardContents);
|
||||||
|
regainOwnership(oldClipboard, newClipboardContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processContents(Clipboard oldClipboard, Transferable newClipboardContents) {
|
||||||
|
try {
|
||||||
|
if (STRING.isAvailable(oldClipboard)) {
|
||||||
|
String stringContent = (String) newClipboardContents.getTransferData(DataFlavor.stringFlavor);
|
||||||
|
for (ClipboardEventListener clipboardEventListener : eventsListener) {
|
||||||
|
clipboardEventListener.onCopyString(stringContent);
|
||||||
|
}
|
||||||
|
} else if (IMAGE.isAvailable(oldClipboard)) {
|
||||||
|
BufferedImage imageContent = ClipboardUtils.convertToBufferedImage((Image) newClipboardContents.getTransferData(DataFlavor.imageFlavor));
|
||||||
|
for (ClipboardEventListener clipboardEventListener : eventsListener) {
|
||||||
|
clipboardEventListener.onCopyImage(imageContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (UnsupportedFlavorException | IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void regainOwnership(Clipboard clipboard, Transferable newClipboardContents) {
|
||||||
|
try {
|
||||||
|
clipboard.setContents(newClipboardContents, this);
|
||||||
|
} catch (IllegalStateException ise) {
|
||||||
|
try {
|
||||||
|
sleep(200);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
regainOwnership(clipboard, newClipboardContents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Transferable currentClipboardContents = clipboard.getContents(null);
|
||||||
|
processContents(clipboard, currentClipboardContents);
|
||||||
|
regainOwnership(clipboard, currentClipboardContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
executorService.submit(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package me.goudham.domain;
|
||||||
|
|
||||||
|
import java.awt.datatransfer.Clipboard;
|
||||||
|
import java.awt.datatransfer.DataFlavor;
|
||||||
|
|
||||||
|
public enum Contents {
|
||||||
|
STRING(DataFlavor.stringFlavor) {
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable(Clipboard clipboard) {
|
||||||
|
return clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IMAGE(DataFlavor.imageFlavor) {
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable(Clipboard clipboard) {
|
||||||
|
return clipboard.isDataFlavorAvailable(DataFlavor.imageFlavor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FILELIST(DataFlavor.javaFileListFlavor) {
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable(Clipboard clipboard) {
|
||||||
|
return clipboard.isDataFlavorAvailable(DataFlavor.javaFileListFlavor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final DataFlavor dataFlavor;
|
||||||
|
|
||||||
|
Contents(DataFlavor dataFlavor) {
|
||||||
|
this.dataFlavor = dataFlavor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataFlavor getDataFlavor() {
|
||||||
|
return dataFlavor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isAvailable(Clipboard clipboard);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package me.goudham.domain;
|
||||||
|
|
||||||
|
public class MyClipboardContent<T> {
|
||||||
|
private T oldContent;
|
||||||
|
|
||||||
|
public MyClipboardContent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOldContent(Object oldContent) {
|
||||||
|
this.oldContent = (T) oldContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getOldContent() {
|
||||||
|
return oldContent;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package me.goudham.domain;
|
||||||
|
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.datatransfer.DataFlavor;
|
||||||
|
import java.awt.datatransfer.Transferable;
|
||||||
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class TransferableImage implements Transferable {
|
||||||
|
|
||||||
|
private final Image image;
|
||||||
|
|
||||||
|
public TransferableImage(@NotNull Image image) {
|
||||||
|
this.image = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
|
||||||
|
if (flavor.equals(DataFlavor.imageFlavor)) {
|
||||||
|
return image;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedFlavorException(flavor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataFlavor[] getTransferDataFlavors() {
|
||||||
|
return new DataFlavor[] { DataFlavor.imageFlavor };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
||||||
|
DataFlavor[] flavors = getTransferDataFlavors();
|
||||||
|
for (DataFlavor dataFlavor : flavors) {
|
||||||
|
if (flavor.equals(dataFlavor)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package me.goudham.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when {@link me.goudham.MyClipboard} detects an operating system which is not {@code Mac} or {@code Windows/*Unix}
|
||||||
|
*/
|
||||||
|
public class UnsupportedSystemException extends Throwable {
|
||||||
|
public UnsupportedSystemException(String exceptionMessage) {
|
||||||
|
super(exceptionMessage);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package me.goudham.listener;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
public interface ClipboardEventListener {
|
||||||
|
void onCopyString(String stringContent);
|
||||||
|
void onCopyImage(BufferedImage imageContent);
|
||||||
|
}
|
Loading…
Reference in New Issue