/******************************************************************************
* *
* Copyright 2016 Subterranean Security *
* *
* 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 com.subterranean_security.crimson.cv.ui.remote;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
import com.subterranean_security.crimson.core.net.stream.remote.RemoteMaster;
import com.subterranean_security.crimson.core.net.stream.remote.ScreenInterface;
import com.subterranean_security.crimson.core.proto.Stream.DirtyBlock;
import com.subterranean_security.crimson.core.proto.Stream.DirtyRect;
import com.subterranean_security.crimson.core.proto.Stream.EventData;
import com.subterranean_security.crimson.viewer.ui.UIUtil;
public class RDArea extends JLabel {
private static final long serialVersionUID = 1L;
private RemoteMaster stream;
private int monitorWidth;
private int monitorHeight;
private double scale;
private int scaledBlockWidth;
private int scaledBlockHeight;
public BufferedImage screenImage;
private RDPanel parent;
public RDArea(RDPanel rdp) {
this.parent = rdp;
initAdapters();
};
public void setMonitorSize(int w, int h) {
monitorHeight = h;
monitorWidth = w;
screenImage = new BufferedImage(w, h, parent.settings.getColorType());
}
/*
* Used to preserve aspect ratio
*/
@Override
public Dimension getPreferredSize() {
Dimension d = this.getParent().getSize();
if (stream == null || d.getWidth() <= 0 || d.getHeight() <= 0) {
return d;
}
double nw = monitorWidth;
double nh = monitorHeight;
double ratio = nw / nh;
if (nw > d.getWidth()) {
nw = d.getWidth();
nh = nw / ratio;
}
if (nh > d.getHeight()) {
nh = d.getHeight();
nw = nh * ratio;
}
scale = (nw / (double) monitorWidth);
scaledBlockWidth = (int) (scale * ScreenInterface.getBlockWidth(monitorWidth));
scaledBlockHeight = (int) (scale * ScreenInterface.getBlockHeight(monitorHeight));
if (!parent.ep.isMoving() && stream.isRunning()) {
screenImage = UIUtil.resize(screenImage, (int) nw, (int) nh);
stream.sendEvent(EventData.newBuilder().setScaleUpdate(scale).build());
}
return new Dimension((int) nw, (int) nh);
}
public void setStream(RemoteMaster stream) {
this.stream = stream;
}
@Override
public void paintComponent(Graphics g) {
g.drawImage(screenImage, 0, 0, this.getWidth(), this.getHeight(), this);
}
/**
* Update a static block
*
* @param db
*/
public void updateScreen(DirtyBlock db) {
int startx = scaledBlockWidth * (db.getBlockId() % ScreenInterface.hBlocks);
int starty = scaledBlockHeight * (db.getBlockId() / ScreenInterface.hBlocks);
ByteArrayOutputStream out = new ByteArrayOutputStream(db.getRGBCount());
for (int i = 0; i < db.getRGBCount(); i++) {
out.write(db.getRGB(i));
}
try {
BufferedImage block = ImageIO.read(new ByteArrayInputStream(out.toByteArray()));
screenImage.getGraphics().drawImage(block, startx, starty, block.getWidth(), block.getHeight(), this);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
repaint(startx, starty, scaledBlockWidth, scaledBlockHeight);
}
/**
* Update an arbitrary rectangle
*
* @param dr
*/
public void updateScreen(DirtyRect dr) {
List<Integer> rgb = dr.getRGBAList();
int r = 0;
for (int j = dr.getSy(); j < dr.getSy() + dr.getH(); j++) {
for (int i = dr.getSx(); i < dr.getSx() + dr.getW(); i++) {
screenImage.setRGB(i, j, rgb.get(r++));
}
}
repaint(dr.getSx(), dr.getSy(), dr.getW(), dr.getH());
}
public BufferedImage screenshot() {
return UIUtil.deepCopy(screenImage);
}
private KeyAdapter ka;
private MouseAdapter ma;
private MouseWheelListener mwl;
private MouseMotionAdapter mma;
private void initAdapters() {
ka = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
stream.sendEvent(EventData.newBuilder().setKeyPressed(e.getKeyCode()).build());
}
@Override
public void keyReleased(KeyEvent e) {
stream.sendEvent(EventData.newBuilder().setKeyReleased(e.getKeyCode()).build());
}
};
mwl = new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
stream.sendEvent(EventData.newBuilder().build());
}
};
mma = new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
stream.sendEvent(EventData.newBuilder().setMouseMovedX((int) (e.getX() / scale))
.setMouseMovedY((int) (e.getY() / scale)).build());
}
@Override
public void mouseDragged(MouseEvent e) {
stream.sendEvent(EventData.newBuilder().build());
}
};
ma = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
stream.sendEvent(EventData.newBuilder().setMousePressed(e.getButton())
.setMouseMovedX((int) (e.getX() / scale)).setMouseMovedY((int) (e.getY() / scale)).build());
}
@Override
public void mouseReleased(MouseEvent e) {
stream.sendEvent(EventData.newBuilder().setMouseReleased(e.getButton()).build());
}
};
}
private boolean keyboardInstalled = false;
private boolean mouseInstalled = false;
public void installKeyAdapters() {
if (!keyboardInstalled) {
keyboardInstalled = true;
addKeyListener(ka);
}
}
public void installMouseAdapters() {
if (!mouseInstalled) {
mouseInstalled = true;
addMouseWheelListener(mwl);
addMouseMotionListener(mma);
addMouseListener(ma);
}
}
public void uninstallKeyAdapters() {
if (keyboardInstalled) {
keyboardInstalled = false;
removeKeyListener(ka);
}
}
public void uninstallMouseAdapters() {
if (mouseInstalled) {
mouseInstalled = false;
removeMouseWheelListener(mwl);
removeMouseMotionListener(mma);
removeMouseListener(ma);
}
}
}