import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
/*
voraussetzung für die funktionalität:
alle auftauchende subklassen von Window müssen das als parameter
übergebene Window als "owner" aufweisen
*/
public final class EventTracer {
private static ObjectOutputStream myObjectOutputStream;
private static FileOutputStream myFileOutputStream;
private static AWTEventListener myAWTEventListener;
// pause zw. einzelnen events
private static long myTime;
// welche events sind überhaupt von interesse?
private static final long myEvents = AWTEvent.ACTION_EVENT_MASK |
AWTEvent.KEY_EVENT_MASK |
AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK;
// in dieser form werden die events erfasst
private static final int EVENT_ACTION = 1;
private static final int EVENT_KEY = 2;
private static final int EVENT_MOUSE = 4;
private static final int EVENT_MOUSE_MOTION = 8;
// true, wenn gerade eine aufzeichnung läuft
private static boolean myIsTraceRunning = false;
// true, wenn gerade eine ausführung der aufgezeichneten events läuft
private static boolean myIsApplyRunning = false;
// var., mit deren hilfe die doppelte erfassung von keyevents vermiden wird
private static boolean myEven = false;
//---------------------------------------------------------------------------
public static void startTracingAWTEvents(final Window window,
final int terminateKey) {
if (isAnythingRunning(window)) return;
new Thread() { public void run() {
JFileChooser fc = new JFileChooser();
fc.setSelectedFile(new File("events.bin"));
fc.setDialogTitle("Ereignisdatei speichern...");
if (fc.showSaveDialog(window) != JFileChooser.APPROVE_OPTION) return;
final String filePath = fc.getSelectedFile().getPath();
myIsTraceRunning = true;
// öffne die beiden benötigten streams
try {
myFileOutputStream = new FileOutputStream(filePath);
myObjectOutputStream = new ObjectOutputStream(myFileOutputStream);
} catch (Exception e) {
myFileOutputStream = null;
myObjectOutputStream = null;
System.out.println("Fehler beim Schreiben der Event-Datei");
e.printStackTrace();
return;
}
myTime = System.currentTimeMillis();
myAWTEventListener = new AWTEventListener() {
public void eventDispatched(AWTEvent e) {
// erfasse je nach 'typ' des events relevante parameter
// fall 1: MouseEvent
if (e instanceof MouseEvent) {
MouseEvent me = (MouseEvent)e;
int x = me.getX(), y = me.getY();
Component c = (Component)me.getSource();
// berechne die zum Window relativen koordinaten der komponente
while ( !(c == window) ) {
x += c.getX();
y += c.getY();
if ( c instanceof Window ) { // wenn die komponente ein window
// oder eine subklasse von window ist...
c = ((Window)c).getOwner(); // 'window' muss der owner sein
x -= window.getX();
y -= window.getY();
} else {
c = c.getParent();
}
}
// schreibe ermittelte daten in datei
try {
myObjectOutputStream.writeShort(EVENT_MOUSE);
myObjectOutputStream.writeInt(me.getID());
myObjectOutputStream.writeShort(x);
myObjectOutputStream.writeShort(y);
myObjectOutputStream.writeInt(me.getModifiers());
} catch (Exception ex) {
System.out.println("Fehler beim schreiben in Datei");
ex.printStackTrace();
}
}
// fall 2: KeyEvent
if (e instanceof KeyEvent) {
// vermeide das (unerklärliche) doppelte erfassen von keyevents
myEven = !myEven;
if (myEven) return;
KeyEvent ke = (KeyEvent)e;
int kc = ke.getKeyCode();
if (kc == terminateKey) stopTracingAWTEvents(window);
try {
myObjectOutputStream.writeShort(EVENT_KEY);
myObjectOutputStream.writeInt(ke.getID());
myObjectOutputStream.writeInt(ke.getKeyCode());
} catch (Exception ex) {
System.out.println("Fehler beim schreiben in Datei");
ex.printStackTrace();
}
}
try {
myObjectOutputStream.writeLong(System.currentTimeMillis() - myTime);
} catch (Exception ex) {
System.out.println("Fehler beim schreiben in Datei");
ex.printStackTrace();
}
myTime = System.currentTimeMillis();
}
};
// füge globalen awtlistener ein
Toolkit.getDefaultToolkit().addAWTEventListener(myAWTEventListener, myEvents);
}}.start();
}
//---------------------------------------------------------------------------
private static void stopTracingAWTEvents(Window window) {
// save all occured awt events to a binary file
try {
myObjectOutputStream.flush();
myFileOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
// remove the global awt event listener
Toolkit.getDefaultToolkit().removeAWTEventListener(myAWTEventListener);
myAWTEventListener = null;
myObjectOutputStream = null;
myFileOutputStream = null;
myIsTraceRunning = false;
JOptionPane.showMessageDialog(window, "Aufzeichnung beendet.");
}
//---------------------------------------------------------------------------
public static void runRecordedEvents(final Window window) {
if (isAnythingRunning(window)) return;
new Thread() { public void run() {
JFileChooser fc = new JFileChooser();
fc.setSelectedFile(new File("events.bin"));
fc.setDialogTitle("Ereignisdatei öffnen...");
if (fc.showOpenDialog(window) != JFileChooser.APPROVE_OPTION) return;
final String filePath = fc.getSelectedFile().getPath();
myIsApplyRunning = true;
FileInputStream fis;
ObjectInputStream ois;
try {
fis = new FileInputStream(filePath);
ois = new ObjectInputStream(fis);
} catch (Exception e) {
fis = null;
ois = null;
System.out.println("Fehler beim Öffnen der Event-Datei");
e.printStackTrace();
return;
}
Robot robot = null;
try {
robot = new Robot();
} catch (Exception e) {
System.out.println("Konnte Robot nicht initialisieren");
e.printStackTrace();
return;
}
int event;
while (true) {
try {
event = (int)ois.readShort();
switch (event) {
case EVENT_MOUSE:
int mouseActID = ois.readInt();
int x = (int)ois.readShort();
int y = (int)ois.readShort();
int modifiers = ois.readInt();
if (mouseActID == MouseEvent.MOUSE_PRESSED)
robot.mousePress(modifiers);
else if (mouseActID == MouseEvent.MOUSE_RELEASED)
robot.mouseRelease(modifiers);
else if (mouseActID == MouseEvent.MOUSE_MOVED)
robot.mouseMove(x + window.getX(), y + window.getY());
break;
case EVENT_KEY:
int keyActID = ois.readInt();
int keyCode = ois.readInt();
if (keyActID == KeyEvent.KEY_PRESSED)
robot.keyPress(keyCode);
else if (keyActID == KeyEvent.KEY_RELEASED)
robot.keyRelease(keyCode);
}
// pause
sleep(ois.readLong());
} catch (Exception ex) {
ex.printStackTrace();
break;
}
}
// gebe control-taste frei
robot.keyRelease(KeyEvent.VK_CONTROL);
myIsApplyRunning = false;
JOptionPane.showMessageDialog(window, "Ausführung beendet.");
}}.start();
}
//---------------------------------------------------------------------------
/// prüfe ob gerade eine aufzeichnung/ausführung läuft
private static boolean isAnythingRunning(Window window) {
// prüfe ob nicht gerade eine aufzeichnung läuft
if (myIsTraceRunning) {
JOptionPane.showMessageDialog(window,
"Es läuft gerade eine Aufzeichnung.");
return true;
}
// prüfe ob nicht gerade eine ausführung der aufzeichnung läuft
if (myIsApplyRunning) {
JOptionPane.showMessageDialog(window,
"Eine Aufzeichnung wird gerade ausgeführt.");
return true;
}
return false;
}
}