/*
* @(#)VirtualWindow.java
*
* Copyright (C) 2002-2003 Matt Albrecht
* groboclown@users.sourceforge.net
* http://groboutils.sourceforge.net
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package net.sourceforge.groboutils.uicapture.v1;
import java.awt.Robot;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelListener;
import java.awt.event.MouseEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.util.LinkedList;
import java.util.Iterator;
import net.sourceforge.groboutils.uicapture.v1.event.ICaptureListener;
import net.sourceforge.groboutils.uicapture.v1.event.CaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.KeyPressedCaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.KeyReleasedCaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.MousePressedCaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.MouseReleasedCaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.MouseMovedCaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.MouseWheelCaptureEvent;
import net.sourceforge.groboutils.uicapture.v1.event.IAllowCapturePassThroughListener;
/**
* A window which covers the whole screen, and does not paint in the background.
* It captures keyboard and mouse events, and sends them to both all registered
* listeners, and to the underlying GUI as well. This transparent window is
* similar to the "glass pane" concept in Swing JFrames.
* <P>
* For the moment, there is no way for listeners to prevent an event from
* being passed to the underlying UI. This needs to be changed.
* <P>
* WARNING: if the screen size is to resize, then this will not work correctly.
*
* @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
* @since Jan 4, 2002
* @version Mar 13, 2002
*/
public class VirtualWindow
implements KeyListener, MouseListener, MouseMotionListener,
MouseWheelListener
{
//-------------------------------------------------------------------------
// Private fields
private LinkedList captureListeners = new LinkedList();
private Robot robot = null;
private VirtualWindowUI window = null;
private boolean enableGlass = true;
private Frame owningFrame = null;
private static final String DEFAULT_TITLE = "UI Capture";
//-------------------------------------------------------------------------
// Constructors
/**
* Create a new VirtualWindow, with the glass enabled.
*
* @exception java.awt.AWTException thrown if a Robot is not supported
* in the current JDK implementation.
*/
public VirtualWindow()
throws java.awt.AWTException
{
this( null, true );
}
/**
* Specify the initial enabled state of the window.
*
* @param enable set to the initial glass pane state.
* @exception java.awt.AWTException thrown if a Robot is not supported
* in the current JDK implementation.
*/
public VirtualWindow( String title, boolean enable )
throws java.awt.AWTException
{
if (title == null)
{
title = DEFAULT_TITLE;
}
this.owningFrame = new Frame( title );
this.owningFrame.setSize( 0, 0 );
// this.owningFrame.show();
// this.owningFrame.hide();
this.window = new VirtualWindowUI( this.owningFrame );
this.robot = new Robot();
this.window.addKeyListener( this );
this.window.addMouseListener( this );
this.window.addMouseMotionListener( this );
this.window.addMouseWheelListener( this );
update();
setGlassEnabled( enable );
}
//-------------------------------------------------------------------------
// Public methods
/**
* Close out all inner instances and shut down the UI
*/
public void dispose()
{
this.window.removeKeyListener( this );
this.window.removeMouseListener( this );
this.window.removeMouseMotionListener( this );
this.window.removeMouseWheelListener( this );
this.window.dispose();
this.owningFrame.dispose();
this.captureListeners.clear();
this.robot = null;
this.window = null;
}
/**
*
* @return the inner Window reference.
*/
public VirtualWindowUI getWindow()
{
return this.window;
}
/**
* Sets the inner state for displaying the glass pane. If the pane is
* enabled, then the glass pane will attempt to maximize itself and
* keep itself on the foreground at all costs.
*
* @param on <tt>true</tt> if the glass pane is enabled (active and
* intercepting events), or <tt>false</tt> if is disabled.
*/
public synchronized void setGlassEnabled( boolean on )
{
this.enableGlass = on;
this.window.setGlassEnabled( on );
}
/**
* Retrieves the current glass enabled state.
*
* @return <tt>true</tt> if the glass pane is enabled (active and
* intercepting events), or <tt>false</tt> if is disabled.
*/
public boolean isGlassEnabled()
{
return this.enableGlass;
}
/**
* Simulates the given captured event. This minimizes the glass window,
* performs the event with the Robot, and restores the glass window if
* the glass pane is enabled.
*
* @param ce the event to simulate.
*/
public synchronized void simulateEvent( CaptureEvent ce )
{
hide();
// ensure that the window is restored, no matter the exception.
try
{
ce.performEvent( this.robot );
}
finally
{
show();
}
}
/**
* Sleeps for the specified number of milliseconds. This is passed
* directly through to the underlying Robot.
*
* @param ms Time to sleep in milliseconds.
* @exception IllegalArgumentException thrown by Robot if <tt>ms</tt> is
* not between 0 and 60,000, inclusive.
*/
public void delay( int ms )
{
this.robot.delay( ms );
}
/**
* Waits until all events currently on the event queue have been processed.
* This is passed directly through to the underlying Robot.
*/
public void waitForIdle()
{
this.robot.waitForIdle();
}
/**
* Scrapes the current screen into a BufferedImage the same size as the
* window.
*
* @return the captured screen image.
*/
public BufferedImage createScreenScrape()
{
return createScreenScrape( this.window.getCoveredScreen() );
}
/**
* Scrapes the current screen into a BufferedImage from the given area
* on the screen. This is passed directly to the underlying Robot.
*
* @return the captured screen image.
*/
public BufferedImage createScreenScrape( Rectangle bounds )
{
// check bounds against the window's bounds
if (bounds == null ||
!this.window.getCoveredScreen().contains( bounds ))
{
throw new IllegalArgumentException("Bounds "+bounds+
" is not within the screen dimension.");
}
// ensure the window is hidden, to get the current screen image,
// then restore the window, no matter the thrown exceptions.
hide();
try
{
return this.robot.createScreenCapture( bounds );
}
finally
{
show();
}
}
/**
* Adds an <tt>ICaptureListener</tt> to the list of recipients of input
* events. If the given listener is <tt>null</tt>, then the request is
* ignored.
*
* @param cl the listener to add.
*/
public void addCaptureListener( ICaptureListener cl )
{
if (cl != null)
{
this.captureListeners.add( cl );
}
}
/**
* Removes the given <tt>ICaptureListener</tt> from the inner list of
* input events recipients. If the given listener is <tt>null</tt> or
* not registered, then the request is ignored.
*
* @param cl the listener to remove.
*/
public void removeCaptureListener( ICaptureListener cl )
{
if (cl != null)
{
this.captureListeners.remove( cl );
}
}
/**
* Hides the glass pane, and stops all input event capturing. This is
* only executed if the glass is enabled, and has no effect on the
* enabled state of the glass.
*/
public void hide()
{
if (this.enableGlass)
{
this.window.hide();
}
}
/**
* Shows the glass pane, and continues all input event capturing. This is
* only executed if the glass is enabled, and has no effect on the
* enabled state of the glass.
*/
public void show()
{
if (this.enableGlass)
{
this.window.show();
}
}
/**
* Updates the background image.
*/
public void update()
{
this.window.setBackground( createScreenScrape() );
}
//-------------------------------------------------------------------------
// Event methods
/**
* @see java.awt.event.MouseWheelListener
*/
public void mouseWheelMoved( MouseWheelEvent me )
{
MouseWheelCaptureEvent ce = new MouseWheelCaptureEvent( me );
Iterator iter = getCaptureListeners();
boolean allow = true;
while (iter.hasNext())
{
ICaptureListener icl = (ICaptureListener)iter.next();
if (icl instanceof IAllowCapturePassThroughListener)
{
if (!((IAllowCapturePassThroughListener)icl).
allowMouseWheelMoved( ce ))
{
allow = false;
}
}
icl.mouseWheelMoved( ce );
}
if (allow)
{
simulateEvent( ce );
}
}
/**
* @see java.awt.event.MouseMotionListener
*/
public void mouseDragged( MouseEvent me )
{
// ignore this method
}
/**
* @see java.awt.event.MouseMotionListener
*/
public void mouseMoved( MouseEvent me )
{
MouseMovedCaptureEvent ce = new MouseMovedCaptureEvent( me );
// do not need to simulate event: the mouse already moved.
// simulateEvent( ce );
Iterator iter = getCaptureListeners();
while (iter.hasNext())
{
((ICaptureListener)iter.next()).mouseMoved( ce );
}
}
/**
* @see java.awt.event.MouseListener
*/
public void mousePressed( MouseEvent me )
{
MousePressedCaptureEvent ce = new MousePressedCaptureEvent( me );
Iterator iter = getCaptureListeners();
boolean allow = true;
while (iter.hasNext())
{
ICaptureListener icl = (ICaptureListener)iter.next();
if (icl instanceof IAllowCapturePassThroughListener)
{
if (!((IAllowCapturePassThroughListener)icl).
allowMousePressed( ce ))
{
allow = false;
}
}
icl.mousePressed( ce );
}
if (allow)
{
simulateEvent( ce );
}
}
/**
* @see java.awt.event.MouseListener
*/
public void mouseReleased( MouseEvent me )
{
MouseReleasedCaptureEvent ce = new MouseReleasedCaptureEvent( me );
Iterator iter = getCaptureListeners();
boolean allow = true;
while (iter.hasNext())
{
ICaptureListener icl = (ICaptureListener)iter.next();
if (icl instanceof IAllowCapturePassThroughListener)
{
if (!((IAllowCapturePassThroughListener)icl).
allowMouseReleased( ce ))
{
allow = false;
}
}
icl.mouseReleased( ce );
}
if (allow)
{
simulateEvent( ce );
}
}
/**
* @see java.awt.event.MouseListener
*/
public void mouseClicked( MouseEvent me )
{
// ignore this method
}
/**
* @see java.awt.event.MouseListener
*/
public void mouseEntered( MouseEvent me )
{
// ignore this method
}
/**
* @see java.awt.event.MouseListener
*/
public void mouseExited( MouseEvent me )
{
// ignore this method
}
/**
* @see java.awt.event.KeyListener
*/
public void keyTyped( KeyEvent me )
{
// ignore this method
}
/**
* @see java.awt.event.KeyListener
*/
public void keyPressed( KeyEvent ke )
{
KeyPressedCaptureEvent ce = new KeyPressedCaptureEvent( ke );
Iterator iter = getCaptureListeners();
boolean allow = true;
while (iter.hasNext())
{
ICaptureListener icl = (ICaptureListener)iter.next();
if (icl instanceof IAllowCapturePassThroughListener)
{
if (!((IAllowCapturePassThroughListener)icl).
allowKeyPressed( ce ))
{
allow = false;
}
}
icl.keyPressed( ce );
}
if (allow)
{
simulateEvent( ce );
}
}
/**
* @see java.awt.event.KeyListener
*/
public void keyReleased( KeyEvent ke )
{
KeyReleasedCaptureEvent ce = new KeyReleasedCaptureEvent( ke );
Iterator iter = getCaptureListeners();
boolean allow = true;
while (iter.hasNext())
{
ICaptureListener icl = (ICaptureListener)iter.next();
if (icl instanceof IAllowCapturePassThroughListener)
{
if (!((IAllowCapturePassThroughListener)icl).
allowKeyReleased( ce ))
{
allow = false;
}
}
icl.keyReleased( ce );
}
if (allow)
{
simulateEvent( ce );
}
}
//-------------------------------------------------------------------------
// Protected methods
/**
* Returns a list of all the current ICaptureListeners.
*
* @return an iterator of the listeners.
*/
protected Iterator getCaptureListeners()
{
return this.captureListeners.iterator();
}
}
|