15.27 Benutzerinteraktionen automatisieren 

Eine besondere Eigenschaft von Präsentationsprogrammen ist die Tatsache, dass Benutzerinteraktionen wie von Zauberhand automatisch vom System vorgenommen werden. Ein Programm kann beispielsweise die Interaktion mit der Maus oder der Tastatur aufnehmen und zu einem späteren Zeitpunkt abspielen. Genau für diese Art der Oberflächensteuerung gibt es die Klasse Robot im Paket AWT. Sie verwaltet eine mit Aktionen gefüllte Ereigniswarteschlange. Die Aktionen werden nacheinander abgearbeitet.
class java.awt.Robot |
- void keyPress( int keycode ) Drückt eine Taste.
- void keyRelease( int keycode ) Lässt die Tasten wieder los.
- void mouseMove( int x, int y ) Bewegt die Maus auf die Koordinate relativ zum aktuellen Fenster.
- void mousePress( int buttons ) Aktiviert eine oder mehrere Maustasten.
- void mouseRelease( int buttons ) Lässt die Maustaste wieder los.
- void delay( int ms ) Wartet Millisekunden. Mehr als 60 Sekunden sind nicht möglich, und das Resultat ist eine IllegalArgumentException.
15.27.1 Automatisch in die Tasten hauen 

Bei den Methoden keyPress(), keyRelease(), mousePress() beziehungsweise mouse-Release() sind die Parameter erklärungsbedürftig. Der Parameter keycode ist der erste, der beachtet werden muss.
Robot rob = new Robot(); rob.keyPress( KeyEvent.VK_SHIFT ); rob.keyPress( KeyEvent.VK_U ); rob.keyPress( 'I' ); rob.keyPress( '0' ); rob.keyPress( '0' ); rob.keyPress( '7' ); rob.keyRelease( KeyEvent.VK_SHIFT ); rob.keyPress( KeyEvent.VK_ENTER ); |
Das Argument von keyPress() und keyRelease() ist eine Konstante der Klasse KeyEvent. Neben den alphanumerischen Tasten auf der Tastatur finden sich unter anderem Konstanten für Funktionstasten, Meta-Tasten, Cursor-Tasten und weitere Sonderzeichen. Die Konstanten für Großbuchstaben und Ziffern decken sich mit den ASCII-Zeichen und können daher alternativ verwendet werden. Bei fast allen Sonderzeichen entspricht die Konstante dem ASCII-Code, doch ist dies nicht selbstverständlich. Die Kleinbuchstaben (ab 0x61) werden zum Beispiel auf den 10er-Block abgebildet (ab 0x60). Ist der übergebene Keycode undefiniert (durch die Konstante KeyEvent.VK_UNDEFINED vorgegeben), so erzeugt der Roboter eine IllegalArgumentException.
Um die Umschalttaste während der Automatisierung einzuschalten, nutzen wir keyPress-(KeyEvent.VK_SHIFT) und lösen die Tasten mit keyRelease(). Das Beispiel macht deutlich, dass das Freigeben nur für Operationen wie zum Beispiel Umschalttaste, VK_ALT und VK_ALT_GRAPH nötig ist, allerdings nicht für normale Buchstaben.
Wird der obere Programmtext in einer grafischen Applikation genutzt, muss sichergestellt sein, dass die Tasten auch die passende Komponente erwischen. Liegt der Fokus zum Beispiel auf einem Rollbalken, werden die Tastendrücke natürlich ohne Wirkung bleiben. Aus diesem Grund ist es angebracht, wieder mit requestFocus() den Fokus zu setzen.
15.27.2 Mausoperationen 

Jetzt fehlen uns noch die Methoden mousePress() und mouseRelease(). Beide erhalten als Argument eine Konstante der Klasse InputEvent: entweder BUTTON1_MASK, BUTTON2_MASK oder BUTTON3_MASK oder eine Kombination aus den dreien wie BUTTON2_MASK | BUTTON3_MASK.
rob.mousePress( InputEvent.BUTTON1_MASK ); rob.delay( 1000 ); rob.mouseRelease( InputEvent.BUTTON1_MASK ); |
Wenn die Mausaktion eine Komponente treffen soll, dann gilt das Gleiche wie für Tastendrücke. Nur muss hier der Fokus nicht auf der Komponente liegen, sondern die Mauskoordinaten müssen auf die Komponente zeigen. Damit die Bildschirmkoordinate einer Komponente ausgelesen werden kann, bietet Component eine Methode getLocation OnScreen() an, die ein Point-Objekt mit den Startkoordinaten liefert. Diese können mit einem kleinen Offset an mouseMove() weitergereicht werden. Dann befindet sich der Zeiger über der Komponente, und mousePress() kann seine Wirkung nicht mehr verfehlen.
15.27.3 Methoden zur Zeitsteuerung 

class java.awt.Robot |
- void setAutoDelay( int ms ) Die Robot-Klasse sendet zum Abspielen Ereignisse an die Oberfläche. Diese Methode setzt die Dauer der Verzögerung fest, die nach dem Ereignis vergehen soll. Mehr als 60 Sekunden sind auch hier nicht gültig.
- int getAutoDelay() Liefert die Zeit, die nach dem Ereignisaufruf vergehen soll.
- void waitForIdle() Wartet, bis alle Ereignisse in der Warteschlange bearbeitet sind.
- void setAutoWaitForIdle( boolean isOn ) Ist isOn = true, wird waitForIdle() nach einem Ereignis aufgerufen.
- boolean isAutoWaitForIdle() Liefert true, falls der Robot automatisch waitForIdle() nach einem Ereignis aufruft.
15.27.4 Screenshots 

Eine sehr interessante Funktion der Robot-Klasse ist createScreenCapture(). Mit ihr lässt sich ein Bildschirmabzug (engl. screenshot) ohne Mauszeiger (zumindest unter Windows, Linux, Solaris und Mac OS X) machen. Die Funktion erwartet als Argument ein Rectangle-Objekt (speichert x, y, height und width), das den zu »fotografierenden« Bereich spezifiziert. Das Ergebnis von createScreenCapture() ist ein BufferedImage-Objekt, das direkt über einen JPEGCodec in eine JPEG-Datei oder mit ImageIO in andere Formate geschrieben werden kann.
Listing 15.75 com/tutego/insel/ui/awt/Screenshot.java
package com.tutego.insel.ui.awt; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; public class Screenshot { public static void main( String[] args ) throws Exception { Thread.sleep( 2000 ); BufferedImage bi = new Robot().createScreenCapture( new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) ); ImageIO.write( bi, "jpg", new File("c:/screenshot.jpg") ); System.exit( 0 ); } }
15.27.5 MouseInfo und PointerInfo 

Mit der Klasse Robot lassen sich zwar Tastatur- und Maus-Ereignisse produzieren und Screen-shots nehmen, doch Informationen über die aktuelle Mausposition liefert die Klasse nicht. Auch das MouseEvent liefert nur die aktuellen relativen Koordinaten bei einem Fenster, doch nicht die Position der Maus auf dem physikalischen Schirm.
Die Klasse MouseInfo liefert diese Information. Die statische Funktion MouseInfo.getPointer Info() liefert ein PointerInfo-Objekt, das Aussagen über die anzeigende Einheit und über die Position des Mauszeigers macht. MouseInfo.getNumberOfButtons() liefert die Anzahl der Knöpfe.
PointerInfo info = MouseInfo.getPointerInfo(); System.out.println( info.getLocation() ); // java.awt.Point[x=633,y=482] System.out.println( info.getDevice() ); // Win32GraphicsDevice[screen=0] System.out.println( MouseInfo.getNumberOfButtons() ); // 5