Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Copying to Clipboard

I am writing simple application in Java. Program gets data from Clipboard, convert it, and send it to Clipboard again. The problem is, that not always this data is send back to clipboard and I dont know why. Could you help me?

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class mainApp {
    DateFormat timeFormat = SimpleDateFormat.getTimeInstance();
    public static void main(String[] args) {
        mainApp app = new mainApp();
        app.menu();
    }

    void menu() {
        int choice = 0;
        while (choice != 2) {
            Scanner reader = new Scanner(System.in);
            System.out.println("1. Get data");
            System.out.println("2. Exit");
            choice = reader.nextInt();
            switch (choice) {
                case 1:
                    getData();
                    break;
                case 2:
                    break;
                default:
                    break;
            }
        }
    }

    void getData() {
        try {
            Process process = Runtime.getRuntime().exec("cpToClipboard.exe");
            System.out.println(timeFormat.format(new Date()) + ": Copying data");

            String data = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
            System.out.println(timeFormat.format(new Date()) + ": Data copied");
            System.out.println(timeFormat.format(new Date()) + ": " + data);
            System.out.println(timeFormat.format(new Date()) + ": Transferring.");

            String dataSplit[] = data.split(";");
            String getTicket = "";
            String getNrShop = "";
            String getNrPSD = "";
            String getPerson = "";
            String getTelephone = "";

            for (String dataSplitted : dataSplit) {
                String dataParameters[] = dataSplitted.split("=");
                switch (dataParameters[0]) {
                    case "TicketNumber":
                        getTicket = dataParameters[1];
                        System.out.println("Ticket number: " + getTicket);
                        break;
                    case "ClientNumber":
                        getNrShop = dataParameters[1];
                        System.out.println("Client number: " + getNrShop);
                        break;
                    case "Client":
                        getNrPSD = dataParameters[1];
                        System.out.println("Client: " + getNrPSD);
                        break;
                    case "Person":
                        getPerson = dataParameters[1];
                        System.out.println("Person: " + getPerson);
                        break;
                    case "Telephone":
                        getTelephone = dataParameters[1];
                        System.out.println("Phone Number: " + getTelephone);
                        break;
                    default:
                        break;
                }
            }

            System.out.println(timeFormat.format(new Date()) + ": Transferred.");

            String cpToClp = getNrShop + " " + getNrPSD + "\nPerson: " + getPerson + ", tel.: " + getTelephone + "\nTicker Number: " + getTicket + "\n";
            System.out.println(timeFormat.format(new Date()) + " " + cpToClp);
            System.out.println(timeFormat.format(new Date()) + ": Copying to Clipboard");

            StringSelection stringSelection = new StringSelection(cpToClp);
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            clipboard.setContents(stringSelection, null);

            System.out.println(timeFormat.format(new Date()) + ": Data copied to clipboard.");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

So. From Clipboard I received data in style: "TicketNumber=517010593;ClientNumber=14:32;Client=0;Person=X‌​YZ XYZ;Telephone=546321635;". My program read it properly. I convert this data so I don't have any "=" or ";". After converting I should receive:

Client name 
Person: Name Surname, tel.: 0530919237: 
Ticket Number: 23264235 

This data should be copied to clipbaord and not always it is copied. For 10 test only 4 or 5 was good. At bad cases clipboard is the same as received from clipboard in first step of my program

like image 486
bugZ Avatar asked Jul 10 '26 10:07

bugZ


1 Answers

When you run Runtime.getRuntime().exec("cpToClipboard.exe") it starts the cpToClipboard command. But it doesn't wait for it to return.

So now your Java program and cpToClipboard are running in parallel, and you have a possible race condition:

  • If it happens that cpToClipboard puts the data in the clipboard before the Java program gets to read it - all is fine - the Java program reads it, and replaces it with what it needs to replace it.

  • But if cpToClipboard writes the data after the Java program tried to read it, the data in the clipboard will be what cpToClipboard placed there.

  • In addition, it's possible that cpToClipboard will put something partial into the clipboard, and then complete it later. So the Java program will read some of it, and then write its result, and then cpToClipboard will write the second part of its output to the clipboard.

In short, when you run in parallel, you need to have special ways to lock away the clipboard. But why run in parallel at all? Normally, I believe you want to wait until cpToClipboard does what it needs and terminates, and only then you want to process the clipboard.

The appropriate way to do that is to call the waitFor() method on the process you got.

Process process = Runtime.getRuntime().exec("cpToClipboard.exe");
int result = process.waitFor();
if ( result == 0 ) {

    // Process the information in the clipboard as you do now

}

(All of this has to be inside the try-catch, of course, as waitFor() also throws InterruptedException in theory).

Using process.destroy() is not the correct way - this kills the subprocess rather than allowing it to work and terminate appropriately.

like image 73
RealSkeptic Avatar answered Jul 12 '26 00:07

RealSkeptic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!