/**
* Copyright 2009 Marc Stogaitis and Mimi Sun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gmote.server.visualtouchpad;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import org.gmote.common.Protocol.MouseEvent;
import org.gmote.server.MouseUtil;
/**
* Represents a single screen tile. Is capable of taking screen shots of itself
* and comparing it with previous screen shots.
*
* @author Marc Stogaitis
*/
public class ScreenTile {
private int idX;
private int idY;
// Location of tile relative to all screens.
private Rectangle tileRect;
private List<Rectangle> boundsWithinIndividualScreen = new ArrayList<Rectangle>();
private List<Screen> screens = new ArrayList<Screen>();
private byte[] lastImageSeen;
public ScreenTile(int idX, int idY, Rectangle tileRect) {
this.idX = idX;
this.idY = idY;
this.tileRect = tileRect;
}
/**
* Tells this tile which screen it is associated with. On single monitor
* systems, this will simply be the main screen. On multi-monitor systems,
* this tile can be split across more than one screen when near a screen
* boundary.
*/
public void addScreen(Screen screen) {
screens.add(screen);
Rectangle screenBounds = screen.getBounds();
Rectangle boundsWithinScreen = new Rectangle(tileRect.x - screenBounds.x, tileRect.y - screenBounds.y, TileHandler.TILE_SIZE, TileHandler.TILE_SIZE);
boundsWithinIndividualScreen.add(boundsWithinScreen);
}
/**
* Takes a screen shot at the position on the screen which this tile
* represents. Returns null if the image has not changed since the last time
* this method was called, or if this is an 'off the screen tile' which can
* happen when you have more than one monitor with different sizes.
*/
public byte[] takeImage() throws IOException {
// TODO(mstogaitis): handle the case where tiles are part of several
// screens.
if (screens.size() == 0) {
return null;
}
Screen screen = screens.get(0);
Robot robot = screen.getRobot();
BufferedImage bufferedImage = robot.createScreenCapture(boundsWithinIndividualScreen.get(0));
ByteArrayOutputStream bas = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "PNG", bas);
byte[] imageData = bas.toByteArray();
// TODO(mstogaitis): Investigate using a hash here
if (Arrays.equals(imageData, lastImageSeen)) {
return null;
} else {
lastImageSeen = imageData;
return imageData;
}
}
public void clickMouse(int pixelOffsetX, int pixelOffsetY, MouseEvent mouseEvent) {
if (screens.size() == 0) {
return;
}
Screen screen = screens.get(0);
Robot robot = screen.getRobot();
Rectangle bounds = boundsWithinIndividualScreen.get(0);
robot.mouseMove(bounds.x + pixelOffsetX, bounds.y + pixelOffsetY);
MouseUtil.doMouseEvent(mouseEvent, robot);
}
public int getIdX() {
return idX;
}
public int getIdY() {
return idY;
}
@Override
public boolean equals(Object obj) {
if((obj == null) || (obj.getClass() != this.getClass())) return false;
ScreenTile otherObj = (ScreenTile)obj;
return otherObj.idX == idX && otherObj.idY == idY;
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + idX;
hash = hash * 29 + idY;
return hash;
}
@Override
public String toString() {
return idX + " " + idY;
}
public void clearImage() {
lastImageSeen = null;
}
}