Text zeitverzögert mit bestimmter Geschwindigkeit schreiben, aber Probleme dabei

Möchte, dass eine Texteingabe zeitverzögert stattfindet, so dass keine Rückschlüsse auf meine Tippgeschwindigkeit von Wörtern gezogen werden können. Zum Beispiel sollen jede 500ms ein Buchstabe getippt werden.

Code:

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayDeque;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class Fenster1 {
	JFrame f1 = new JFrame();
	JFrame f2 = new JFrame();
	JTextArea a1 = new JTextArea();
	ArrayDeque<KeyEvent> que = new ArrayDeque<KeyEvent>();

	Fenster1() {
		f1.add(a1);
		f1.setSize(400, 400);
		f1.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		f1.setVisible(true);

		f2.setSize(100, 100);
		f2.setLocation(450, 1);
		f2.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		f2.setVisible(true);

		f2.addKeyListener(new KeyListener() {
			@Override
			public void keyTyped(KeyEvent e) {
				e.setSource(a1);
				synchronized (que) {
					que.offer(e);
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
			}

			@Override
			public void keyPressed(KeyEvent e) {
			}
		});

		new Thread(new Runnable() {
			@Override
			public void run() {
				while (f1.isVisible()) {
					synchronized (que) {
						if (!que.isEmpty()) {
							SwingUtilities.invokeLater(new Runnable() {
								@Override
								public void run() {
									int p = a1.getText().length() ;
									a1.setCaretPosition(p);
									a1.dispatchEvent(que.poll());
								}
							});
						}
					}
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						break;
					}
				}
			}
		}).start();
	}

	public static void main(String[] args) {
		new Fenster1();
	}
}

Mit e.setSource(a1); ändere ich den Eigentümer des Events und mit a1.dispatchEvent(e); gebe ich das Event weiter.

Probleme: Der Text wird erst geschrieben, wenn f1 den Fokus hat; und anstatt „hallo“ wird zum Beispiel „loalh“ geschrieben. Hat jemand einen Tipp?

/e Wenn ich das Event im KeyListener ohne Threads direkt umleite, funktioniert alles prima… nur eben nicht zeitverzögert.

Neue Variante:

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayDeque;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;

public class Fenster1 {
	public static class Offset {
		long c1 = System.currentTimeMillis();
		long c2 = 0;

		synchronized long getOffset() {
			c2++;
			long m = (c1 + c2 * 1000) - System.currentTimeMillis();
			return m > 0 ? m : 0;
		}
	}

	volatile Offset o1 = new Offset();
	JFrame f1 = new JFrame();
	JFrame f2 = new JFrame();
	JTextArea a1 = new JTextArea();

	Fenster1() {
		f1.add(a1);
		f1.setSize(400, 400);
		f1.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		f1.setVisible(true);

		f2.setSize(100, 100);
		f2.setLocation(450, 1);
		f2.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		f2.setVisible(true);

		f2.addKeyListener(new KeyAdapter() {
			@Override
			public void keyTyped(KeyEvent e) {
				new Thread(new Runnable() {
					@Override
					public void run() {
						try {
							Thread.sleep(o1.getOffset());
							e.setSource(a1);
							a1.dispatchEvent(e);
						} catch (InterruptedException e1) {
							e1.printStackTrace();
						}
					}
				}).start();
			}
		});
	}

	public static void main(String[] args) {
		new Fenster1();
	}
}

Leider ist die Ausgabe unregelmäßig jetzt nur, wenn man in die JTextArea klickt.

Der Trigger (das KeyEvent „keyTyped“) scheint (beim AWT Event Handling) nicht das einzige Event zu sein und auch nicht das erste, wenn man etwas in ein Textfeld eintippt. Da muss noch mehr geschehen… Außerdem verhält sich das Textfeld anscheinend anders, wenn es nicht im Vordergrund ist.

Habt ihr vielleicht noch eine Idee?

Also, ich möchte eine zeitverzögerte Eingabe, während ich etwas tippe.

Spricht etwas dagegen, statt dem Event einfach den Keychar in die Queue zu stecken und dann mittels append den dann anzuhängen?
Hab es mal ausprobiert funktioniert super

Ja, das geht auch, für meine Zwecke reicht das, Danke Dir. :slight_smile: Ich hatte nur an Tastencombos gedacht, aber damit wäre es ohnehin schwer geworden…

Ich hab noch etwas herausgefunden, aber Windows macht nach einiger Zeit dabei einen Strich durch die Rechnung…
Also, man könnte den Text ja aus einer Textdatei lesen, ihn die Zwischenablage packen, und dann den Inhalt der Zwischenablage mittels Robot und Strg+V (etwas zeitverzögert) einfügen:

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Test2 {
	public static void main(String[] args) throws IOException, AWTException, InterruptedException {
		Robot rob = new Robot();
		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		Thread.sleep(20000);
		BufferedReader reader = new BufferedReader(new FileReader("path\\to\\textfile"));
		int s;
		while ((s = reader.read()) != -1) {
			char c = (char) s;
			StringSelection stringSelection = new StringSelection(String.valueOf(c));
			clipboard.setContents(stringSelection, stringSelection);

			Thread.sleep(100);
			rob.keyPress(KeyEvent.VK_CONTROL);
			rob.keyPress(KeyEvent.VK_V);
			Thread.sleep(100);
			rob.keyRelease(KeyEvent.VK_V);
			rob.keyRelease(KeyEvent.VK_CONTROL);
		}
		reader.close();
	}
}

Probiert es mal aus. Wie gesagt, Windows stellt sich nach einiger Zeit dabei quer, wenn die Zwischenablage so exzessiv genutzt wird… (Mögliches Sicherheitsrisiko oder einfach Windows? :smiley: )

Ok. Den Grund, warum du das in die Zwischenablage packst - anstatt in sowas wie … hmmm … ne Variable(??) würde mich dann jetzt doch mal interessieren.

Der „einzufügende/zu schreibende“ Text enthält viele Sonderzeichen und Groß- und Kleinbuchstaben. Robot verlangt bei keyPress usw. einen so genannten keyCode. Wenn man über KeyStrokes oder java.awt.event.KeyEvent.getExtendedKeyCodeForChar(charCode) an diesen keyCode gelangen möchte, gelangt man irgendwann in Teufels Küche. :neutral_face: Deshalb würde es so nicht funktionieren.

Hier mal eine Demo:

https://www.youtube.com/watch?v=BENtgvg4qIc