├── .classpath ├── .gitignore ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── README.md └── src ├── AutoBot.java ├── ImageSender.java ├── RemoteDataServer.java ├── ServerListener.java ├── ServerWindow.java └── messages └── Constants.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | DesktopRemoteServer 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Mon Jan 03 22:35:30 PST 2011 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.6 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.6 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remote Desktop Server v1.5 2 | 3 | Copyright 2010 Justin Taylor 4 | This software can be distributed under the terms of the 5 | GNU General Public License. 6 | 7 | Receives messages via UDP socket alowing a remote device to control any 8 | computer's peripherals. 9 | 10 | The server has a UI that allows the user the specify a port to listen on, 11 | then waits for a connection from the Andoird device. There are two classes 12 | to the server. 13 | 14 | ## Deliverables 15 | What's that? You just want to use the app!?! You don't want to mess with the 16 | hassle of eclipse? In that case just download 17 | http://central.tayloredapps.org/server.jar and run it on any desktop that has 18 | JRE installed. Then mosy on over and download 19 | http://central.tayloredapps.org/Android-remote-client.apk to your android 20 | device. 21 | 22 | Now that you have everything you need, open the server on the Desktop you are 23 | trying to connect to and click connect. Then open up the app on your mobile 24 | deivce. Make sure the IP address field matches the IP listed on your desktop 25 | server. Then click connect. Now, you are ready to control your dekstop. 26 | 27 | 1. ServerWindow 28 | This class contains both the GUI and the server. Messages from 29 | the Android device is received on the server thread then passed 30 | to and AutoBot object (See section 1.b below). 31 | 32 | 1. AutoBot 33 | Receives messages from the server thread and translates them to 34 | I/O interactions (Move Mouse, Keyboard key stroke). The messages constant file 35 | defines what messages are recognized. 36 | -------------------------------------------------------------------------------- /src/AutoBot.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Justin Taylor 2 | // This software can be distributed under the terms of the 3 | // GNU General Public License. 4 | 5 | /* 6 | * TODO: 7 | * an AutoBot Listener class will need to be made to listen 8 | * for events to send images back and forth 9 | */ 10 | 11 | import java.awt.*; 12 | 13 | import java.awt.Robot; 14 | import java.awt.MouseInfo; 15 | import java.awt.event.InputEvent; 16 | import java.awt.event.KeyEvent; 17 | import java.awt.Rectangle; 18 | import java.awt.image.BufferedImage; 19 | 20 | import messages.Constants; 21 | 22 | public class AutoBot { 23 | 24 | private Robot robot; 25 | 26 | int lastXpos = 0; 27 | int lastYpos = 0; 28 | 29 | int lastScrollY; 30 | 31 | public AutoBot(){ 32 | try{ robot = new Robot(); } 33 | catch(Exception e){ System.out.println("Couldn't Create robot");} 34 | } 35 | 36 | public void handleMessage(String event){ 37 | 38 | try{ 39 | char eventcode = event.charAt(0); 40 | switch(eventcode){ 41 | case Constants.LEFTCLICK: robot.mousePress( InputEvent.BUTTON1_MASK ); 42 | robot.mouseRelease( InputEvent.BUTTON1_MASK ); break; 43 | case Constants.LEFTMOUSEDOWN: robot.mousePress( InputEvent.BUTTON1_MASK ); break; 44 | case Constants.LEFTMOUSEUP: robot.mouseRelease( InputEvent.BUTTON1_MASK ); break; 45 | 46 | case Constants.RIGHTMOUSEDOWN: robot.mousePress( InputEvent.BUTTON3_MASK ); break; 47 | case Constants.RIGHTMOUSEUP: robot.mouseRelease( InputEvent.BUTTON3_MASK ); break; 48 | 49 | case Constants.SCROLLUP: robot.mouseWheel(1); break; 50 | case Constants.SCROLLDOWN: robot.mouseWheel(-1); break; 51 | 52 | case Constants.MOVEMOUSE: Point p = Constants.parseMoveMouseMessage(event); 53 | moveMouse(p.x, p.y); break; 54 | 55 | case Constants.KEYBOARD: type(event.charAt(1)); break; 56 | case Constants.KEYCODE: specialKey(Integer.parseInt(event.substring(1))); break; 57 | 58 | default: System.out.println("ELSE:" + event); break; 59 | } 60 | 61 | }catch(Exception e){ e.printStackTrace(); System.out.println("error here "+event); } 62 | } 63 | 64 | public void moveMouse(int x, int y){ 65 | try{ 66 | //get the current position of the mouse cursor 67 | int current_x_local = MouseInfo.getPointerInfo().getLocation().x; 68 | int current_y_local = MouseInfo.getPointerInfo().getLocation().y; 69 | 70 | //move the mouse relative to the current position 71 | robot.mouseMove(current_x_local + x, current_y_local + y); 72 | }catch(NullPointerException e){ 73 | // Not sure why this exception occurs 74 | System.out.print("NUll pointer exception on mouse move"); 75 | } 76 | } 77 | 78 | public void specialKey(int key_code){ 79 | int key; 80 | 81 | switch(key_code){ 82 | case 19: key = KeyEvent.VK_UP; break; 83 | case 20: key = KeyEvent.VK_DOWN; break; 84 | case 21: key = KeyEvent.VK_LEFT; break; 85 | case 22: key = KeyEvent.VK_RIGHT; break; 86 | 87 | case 66: key = KeyEvent.VK_ENTER; break; 88 | case 67: key = KeyEvent.VK_BACK_SPACE; break; 89 | default: key = -1; break; 90 | } 91 | keyBoardPress(key); 92 | } 93 | 94 | public void type(char character) { 95 | switch (character) { 96 | case 'a': keyBoardPress(KeyEvent.VK_A); break; 97 | case 'b': keyBoardPress(KeyEvent.VK_B); break; 98 | case 'c': keyBoardPress(KeyEvent.VK_C); break; 99 | case 'd': keyBoardPress(KeyEvent.VK_D); break; 100 | case 'e': keyBoardPress(KeyEvent.VK_E); break; 101 | case 'f': keyBoardPress(KeyEvent.VK_F); break; 102 | case 'g': keyBoardPress(KeyEvent.VK_G); break; 103 | case 'h': keyBoardPress(KeyEvent.VK_H); break; 104 | case 'i': keyBoardPress(KeyEvent.VK_I); break; 105 | case 'j': keyBoardPress(KeyEvent.VK_J); break; 106 | case 'k': keyBoardPress(KeyEvent.VK_K); break; 107 | case 'l': keyBoardPress(KeyEvent.VK_L); break; 108 | case 'm': keyBoardPress(KeyEvent.VK_M); break; 109 | case 'n': keyBoardPress(KeyEvent.VK_N); break; 110 | case 'o': keyBoardPress(KeyEvent.VK_O); break; 111 | case 'p': keyBoardPress(KeyEvent.VK_P); break; 112 | case 'q': keyBoardPress(KeyEvent.VK_Q); break; 113 | case 'r': keyBoardPress(KeyEvent.VK_R); break; 114 | case 's': keyBoardPress(KeyEvent.VK_S); break; 115 | case 't': keyBoardPress(KeyEvent.VK_T); break; 116 | case 'u': keyBoardPress(KeyEvent.VK_U); break; 117 | case 'v': keyBoardPress(KeyEvent.VK_V); break; 118 | case 'w': keyBoardPress(KeyEvent.VK_W); break; 119 | case 'x': keyBoardPress(KeyEvent.VK_X); break; 120 | case 'y': keyBoardPress(KeyEvent.VK_Y); break; 121 | case 'z': keyBoardPress(KeyEvent.VK_Z); break; 122 | case 'A': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_A); break; 123 | case 'B': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_B); break; 124 | case 'C': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_C); break; 125 | case 'D': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_D); break; 126 | case 'E': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_E); break; 127 | case 'F': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_F); break; 128 | case 'G': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_G); break; 129 | case 'H': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_H); break; 130 | case 'I': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_I); break; 131 | case 'J': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_J); break; 132 | case 'K': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_K); break; 133 | case 'L': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_L); break; 134 | case 'M': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_M); break; 135 | case 'N': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_N); break; 136 | case 'O': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_O); break; 137 | case 'P': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_P); break; 138 | case 'Q': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_Q); break; 139 | case 'R': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_R); break; 140 | case 'S': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_S); break; 141 | case 'T': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_T); break; 142 | case 'U': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_U); break; 143 | case 'V': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_V); break; 144 | case 'W': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_W); break; 145 | case 'X': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_X); break; 146 | case 'Y': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_Y); break; 147 | case 'Z': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_Z); break; 148 | case '`': keyBoardPress(KeyEvent.VK_BACK_QUOTE); break; 149 | case '0': keyBoardPress(KeyEvent.VK_0); break; 150 | case '1': keyBoardPress(KeyEvent.VK_1); break; 151 | case '2': keyBoardPress(KeyEvent.VK_2); break; 152 | case '3': keyBoardPress(KeyEvent.VK_3); break; 153 | case '4': keyBoardPress(KeyEvent.VK_4); break; 154 | case '5': keyBoardPress(KeyEvent.VK_5); break; 155 | case '6': keyBoardPress(KeyEvent.VK_6); break; 156 | case '7': keyBoardPress(KeyEvent.VK_7); break; 157 | case '8': keyBoardPress(KeyEvent.VK_8); break; 158 | case '9': keyBoardPress(KeyEvent.VK_9); break; 159 | case '-': keyBoardPress(KeyEvent.VK_MINUS); break; 160 | case '=': keyBoardPress(KeyEvent.VK_EQUALS); break; 161 | case '~': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_QUOTE); break; 162 | case '!': keyBoardPress(KeyEvent.VK_EXCLAMATION_MARK); break; 163 | case '@': keyBoardPress(KeyEvent.VK_AT); break; 164 | case '#': keyBoardPress(KeyEvent.VK_NUMBER_SIGN); break; 165 | case '$': keyBoardPress(KeyEvent.VK_DOLLAR); break; 166 | case '%': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_5); break; 167 | case '^': keyBoardPress(KeyEvent.VK_CIRCUMFLEX); break; 168 | case '&': keyBoardPress(KeyEvent.VK_AMPERSAND); break; 169 | case '*': keyBoardPress(KeyEvent.VK_ASTERISK); break; 170 | case '(': keyBoardPress(KeyEvent.VK_LEFT_PARENTHESIS); break; 171 | case ')': keyBoardPress(KeyEvent.VK_RIGHT_PARENTHESIS); break; 172 | case '_': keyBoardPress(KeyEvent.VK_UNDERSCORE); break; 173 | case '+': keyBoardPress(KeyEvent.VK_PLUS); break; 174 | case '\t': keyBoardPress(KeyEvent.VK_TAB); break; 175 | case '\n': keyBoardPress(KeyEvent.VK_ENTER); break; 176 | case '[': keyBoardPress(KeyEvent.VK_OPEN_BRACKET); break; 177 | case ']': keyBoardPress(KeyEvent.VK_CLOSE_BRACKET); break; 178 | case '\\': keyBoardPress(KeyEvent.VK_BACK_SLASH); break; 179 | case '{': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_OPEN_BRACKET); break; 180 | case '}': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_CLOSE_BRACKET); break; 181 | case '|': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_SLASH); break; 182 | case ';': keyBoardPress(KeyEvent.VK_SEMICOLON); break; 183 | case ':': keyBoardPress(KeyEvent.VK_COLON); break; 184 | case '\'': keyBoardPress(KeyEvent.VK_QUOTE); break; 185 | case '"': keyBoardPress(KeyEvent.VK_QUOTEDBL); break; 186 | case ',': keyBoardPress(KeyEvent.VK_COMMA); break; 187 | case '<': keyBoardPress(KeyEvent.VK_LESS); break; 188 | case '.': keyBoardPress(KeyEvent.VK_PERIOD); break; 189 | case '>': keyBoardPress(KeyEvent.VK_GREATER); break; 190 | case '/': keyBoardPress(KeyEvent.VK_SLASH); break; 191 | case '?': keyBoardPress(KeyEvent.VK_SHIFT, KeyEvent.VK_SLASH); break; 192 | case ' ': keyBoardPress(KeyEvent.VK_SPACE); break; 193 | default: System.out.println("Character " + character); break; 194 | } 195 | } 196 | 197 | public void keyBoardPress(int key){ 198 | try{ 199 | robot.keyPress(key); 200 | robot.keyRelease(key); 201 | }catch(Exception e){} 202 | } 203 | 204 | public void keyBoardPress(int key, int key2){ 205 | try{ 206 | robot.keyPress(key); 207 | robot.keyPress(key2); 208 | robot.keyRelease(key2); 209 | robot.keyRelease(key); 210 | 211 | }catch(Exception e){} 212 | } 213 | 214 | public BufferedImage getScreenCap(int width, int height){ 215 | 216 | // get the current location of the mouse 217 | // this is used to actually draw the mouse 218 | Point mousePosition = MouseInfo.getPointerInfo().getLocation(); 219 | 220 | int x = (int) (mousePosition.x - (width * 0.5)); 221 | int y = (int) (mousePosition.y - (height * 0.5)); 222 | 223 | Rectangle captureSize = new Rectangle(x, y, width, height); 224 | BufferedImage img = robot.createScreenCapture(captureSize); 225 | // start drawing the mouse onto the image; 226 | Polygon pointer = new Polygon(new int[]{0, -4, 4},new int[]{0, 8, 8}, 3); 227 | 228 | Graphics2D grfx = img.createGraphics(); 229 | grfx.translate((width * 0.5), (height * 0.5)); 230 | grfx.setColor( new Color(100,100,255,255) ); 231 | grfx.fillPolygon( pointer ); 232 | grfx.setColor( Color.red ); 233 | grfx.drawPolygon( pointer ); 234 | grfx.dispose(); 235 | 236 | return img; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/ImageSender.java: -------------------------------------------------------------------------------- 1 | import java.awt.Graphics2D; 2 | import java.awt.RenderingHints; 3 | import java.awt.geom.AffineTransform; 4 | import java.awt.image.BufferedImage; 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.net.DatagramPacket; 8 | import java.net.DatagramSocket; 9 | import java.net.InetAddress; 10 | import java.util.Iterator; 11 | 12 | import javax.imageio.IIOImage; 13 | import javax.imageio.ImageIO; 14 | import javax.imageio.ImageWriteParam; 15 | import javax.imageio.ImageWriter; 16 | import javax.imageio.stream.ImageOutputStream; 17 | 18 | public class ImageSender implements Runnable{ 19 | 20 | private InetAddress clientAddr; 21 | private int clientPort; 22 | private DatagramSocket socket; 23 | public boolean connected = false; 24 | 25 | public static final float SIZETHRESHOLD = 100f; 26 | 27 | private BufferedImage img; 28 | 29 | public ImageSender(String ip, int port){ 30 | try{ 31 | clientAddr = InetAddress.getByName(ip); 32 | } 33 | catch (Exception e){ 34 | System.out.print("Exception setting ip address"); 35 | } 36 | 37 | clientPort = port; 38 | 39 | try { 40 | socket = new DatagramSocket(); 41 | connected = true; 42 | 43 | } 44 | catch (Exception e) { 45 | System.out.print("Could not bind to a port"); 46 | } 47 | } 48 | 49 | public ImageSender(InetAddress ip, int port){ 50 | clientAddr = ip; 51 | clientPort = port; 52 | 53 | try { 54 | socket = new DatagramSocket(); 55 | connected = true; 56 | 57 | } 58 | catch (Exception e) { 59 | System.out.print("Could not bind to a port"); 60 | } 61 | } 62 | 63 | public void setImage(BufferedImage image) 64 | { 65 | img = image; 66 | } 67 | 68 | public void setPort(int port) 69 | { 70 | clientPort = port; 71 | } 72 | 73 | public void run(){ 74 | ByteArrayOutputStream buffer; 75 | 76 | try{ 77 | ByteArrayOutputStream tmp = compressImage(img, 1.0f); 78 | ImageIO.write(img, "jpeg", tmp); 79 | tmp.close(); 80 | 81 | int contentLength = tmp.size(); 82 | float compress = 64000.0f/contentLength; 83 | System.out.println("Compress size "+compress); 84 | 85 | if(compress > 1.0) { 86 | buffer = tmp; 87 | } else { 88 | buffer = compressImage(img, compress); 89 | } 90 | 91 | }catch(IOException e){ 92 | System.out.println(e); 93 | return; 94 | } 95 | 96 | byte[] data = buffer.toByteArray(); 97 | DatagramPacket out = new DatagramPacket(data, data.length, clientAddr, clientPort); 98 | 99 | try { 100 | socket.send(out); 101 | buffer.close(); 102 | } catch (IOException e) { 103 | System.out.println("Data Length = "+data.length); 104 | e.printStackTrace(); 105 | } 106 | } 107 | 108 | private BufferedImage scaleImage(BufferedImage image, int width, int height) 109 | { 110 | BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 111 | // Paint scaled version of image to new image 112 | Graphics2D graphics2D = scaledImage.createGraphics(); 113 | 114 | graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 115 | graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 116 | graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 117 | 118 | 119 | graphics2D.drawImage(image, 0, 0, width, height, null); 120 | graphics2D.dispose(); 121 | return scaledImage; 122 | } 123 | 124 | private BufferedImage scaleImage(BufferedImage image, int width, int height, float scale) 125 | { 126 | BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 127 | // Paint scaled version of image to new image 128 | Graphics2D graphics2D = scaledImage.createGraphics(); 129 | AffineTransform xform = AffineTransform.getScaleInstance(scale, scale); 130 | 131 | graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 132 | graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 133 | graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 134 | 135 | 136 | graphics2D.drawImage(image, xform, null); 137 | 138 | graphics2D.dispose(); 139 | return scaledImage; 140 | } 141 | 142 | 143 | /* 144 | * 145 | * Compression 146 | * 147 | */ 148 | private ByteArrayOutputStream compressImage(BufferedImage image, float quality) throws IOException 149 | { 150 | // Get a ImageWriter for jpeg format. 151 | Iterator writers = ImageIO.getImageWritersBySuffix("jpeg"); 152 | if (!writers.hasNext()) throw new IllegalStateException("No writers found"); 153 | ImageWriter writer = (ImageWriter) writers.next(); 154 | 155 | while(!writer.getDefaultWriteParam().canWriteCompressed() && writers.next() != null) 156 | { 157 | writer = writers.next(); 158 | } 159 | 160 | 161 | // Create the ImageWriteParam to compress the image. 162 | ImageWriteParam param = writer.getDefaultWriteParam(); 163 | 164 | param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 165 | param.setCompressionQuality(quality); 166 | 167 | // The output will be a ByteArrayOutputStream (in memory) 168 | ByteArrayOutputStream bos = new ByteArrayOutputStream(32768); 169 | ImageOutputStream ios = ImageIO.createImageOutputStream(bos); 170 | writer.setOutput(ios); 171 | writer.write(null, new IIOImage(image, null, null), param); 172 | ios.flush(); 173 | 174 | return bos; 175 | 176 | /* 177 | // otherwise the buffer size will be zero! 178 | // From the ByteArrayOutputStream create a RenderedImage. 179 | ByteArrayInputStream in = new ByteArrayInputStream(bos.toByteArray()); 180 | RenderedImage out = ImageIO.read(in); 181 | int size = bos.toByteArray().length; 182 | showImage("Compressed to " + quality + ": " + size + " bytes", out); 183 | */ 184 | } 185 | 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/RemoteDataServer.java: -------------------------------------------------------------------------------- 1 | 2 | import java.net.BindException; 3 | import java.net.DatagramPacket; 4 | import java.net.DatagramSocket; 5 | import java.net.InetAddress; 6 | 7 | import messages.Constants; 8 | 9 | public class RemoteDataServer implements Runnable{ 10 | 11 | // local settings 12 | private int PORT; 13 | private InetAddress ipAddress; 14 | 15 | 16 | //remote settings 17 | private int clientPort; 18 | private InetAddress listenerAddress; 19 | 20 | private DatagramSocket server; 21 | private byte[] buf; 22 | private DatagramPacket dgp; 23 | 24 | private String message; 25 | private AutoBot bot; 26 | 27 | private ServerListener window; 28 | 29 | private ImageSender sender; 30 | 31 | 32 | public RemoteDataServer(int port){ 33 | PORT = port; 34 | buf = new byte[1000]; 35 | dgp = new DatagramPacket(buf, buf.length); 36 | bot = new AutoBot(); 37 | } 38 | 39 | public RemoteDataServer(){ 40 | buf = new byte[1000]; 41 | dgp = new DatagramPacket(buf, buf.length); 42 | bot = new AutoBot(); 43 | } 44 | 45 | public void setPort(int port){ PORT = port; } 46 | 47 | public void setClientPort(int port){ clientPort = port; } 48 | 49 | public void setIP(InetAddress inet){ ipAddress = inet; } 50 | 51 | public void setServerListener(ServerListener listener){ window = listener; } 52 | 53 | public void shutdown(){ 54 | try{ server.close(); } 55 | catch(Exception e){} 56 | } 57 | 58 | public void run(){ 59 | boolean connected = false; 60 | try { 61 | server = new DatagramSocket(PORT, ipAddress); 62 | connected = true; 63 | } 64 | catch(BindException e){ 65 | setListenerMessage("Port "+PORT+" is already in use. Use a different Port"); 66 | setConnectButtonEnabled(false); 67 | } 68 | catch(Exception e){ 69 | setListenerMessage("Unable to connect"); 70 | setConnectButtonEnabled(false); 71 | } 72 | 73 | while(connected){ 74 | // get message from sender 75 | try{ server.receive(dgp); 76 | 77 | // store the packets address for sending images out 78 | listenerAddress = dgp.getAddress(); 79 | // translate and use the message to automate the desktop 80 | message = new String(dgp.getData(), 0, dgp.getLength()); 81 | if (message.equals("Connectivity")) 82 | { 83 | setListenerMessage("Trying to Connect"); 84 | server.send(dgp); //echo the message back 85 | } 86 | 87 | else if(message.equals("Connected")) 88 | { 89 | server.send(dgp); //echo the message back 90 | } 91 | 92 | else if(message.equals("Close")) 93 | { 94 | setListenerMessage("Controller has Disconnected. Trying to reconnect."); //echo the message back 95 | } 96 | 97 | else if(message.charAt(0) == Constants.REQUESTIMAGE) 98 | { 99 | 100 | String[] arr = message.split(Constants.DELIMITER+""); 101 | System.out.print(arr[1]+" "+arr[2]+"\n"); 102 | sendImage(Integer.parseInt(arr[1]), Integer.parseInt(arr[2])); 103 | } 104 | 105 | else 106 | { 107 | setListenerMessage("Connected to Controller"); 108 | bot.handleMessage(message); 109 | } 110 | }catch(Exception e){ 111 | System.out.println(e); 112 | setListenerMessage("Disconnected"); 113 | setConnectButtonEnabled(false); 114 | connected = false; 115 | } 116 | } 117 | } 118 | 119 | private void setListenerMessage(String msg){ 120 | if(window != null){ 121 | window.setMessage(msg); 122 | } 123 | } 124 | 125 | private void setConnectButtonEnabled(boolean enable){ 126 | if(window != null){ 127 | window.setConnectButtonEnabled(enable); 128 | } 129 | } 130 | 131 | public void sendImage(int width, int height){ 132 | if(sender == null && listenerAddress != null) 133 | { 134 | sender = new ImageSender(listenerAddress, clientPort); 135 | } 136 | 137 | if(sender != null) 138 | { 139 | 140 | float scale = 0.5f; 141 | if(width > height) { 142 | scale = ImageSender.SIZETHRESHOLD/width; 143 | }else{ 144 | scale = ImageSender.SIZETHRESHOLD/height; 145 | } 146 | 147 | sender.setPort(clientPort); 148 | //sender.setImage(bot.getScreenCap((int)Math.round(width*scale), (int)Math.round(height * scale)) ); 149 | 150 | sender.setImage(bot.getScreenCap(width, height)); 151 | 152 | Thread send_image_thread = new Thread(sender); 153 | send_image_thread.start(); 154 | } 155 | } 156 | 157 | 158 | } -------------------------------------------------------------------------------- /src/ServerListener.java: -------------------------------------------------------------------------------- 1 | 2 | public abstract class ServerListener { 3 | abstract void setMessage(String message); 4 | abstract void setConnectButtonEnabled(boolean enable); 5 | } -------------------------------------------------------------------------------- /src/ServerWindow.java: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Justin Taylor 2 | // This software can be distributed under the terms of the 3 | // GNU General Public License. 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.*; 8 | import java.io.IOException; 9 | import java.net.*; 10 | import java.util.Collections; 11 | import java.util.Enumeration; 12 | 13 | public class ServerWindow extends ServerListener implements ActionListener{ 14 | 15 | public RemoteDataServer server; 16 | 17 | private Thread sThread; //server thread 18 | 19 | private static final int WINDOW_HEIGHT = 275; 20 | private static final int WINDOW_WIDTH = 350; 21 | 22 | private String ipAddress; 23 | 24 | private JFrame window = new JFrame("Remote Desktop Server"); 25 | 26 | private JLabel addressLabel = new JLabel(""); 27 | private JLabel portLabel = new JLabel("PORT: "); 28 | private JLabel clientPortLabel = new JLabel("Outgoing PORT: "); 29 | 30 | private JTextArea[] buffers = new JTextArea[4]; 31 | private JTextField portTxt = new JTextField(5); 32 | 33 | private JTextField clientPortTxt = new JTextField(5); 34 | private JTextField ipTxt = new JTextField(10); 35 | private JLabel serverMessages = new JLabel("Not Connected"); 36 | 37 | private JButton connectButton = new JButton("Connect"); 38 | private JButton disconnectButton = new JButton("Disconnect"); 39 | private JButton shutdownButton = new JButton("Shutdown"); 40 | 41 | 42 | public ServerWindow(){ 43 | 44 | server = new RemoteDataServer(); 45 | server.setServerListener( this ); 46 | 47 | window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT); 48 | window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 49 | 50 | connectButton.addActionListener(this); 51 | disconnectButton.addActionListener(this); 52 | //shutdownButton.addActionListener(this); 53 | 54 | Container c = window.getContentPane(); 55 | c.setLayout(new FlowLayout()); 56 | 57 | try{ 58 | InetAddress ip = getIpAddress(); 59 | ipAddress = ip.getHostAddress(); 60 | addressLabel.setText("IP Address: "); 61 | ipTxt.setText(ipAddress); 62 | } 63 | catch(Exception e){addressLabel.setText("IP Address Could Not be Resolved, Try typing in the IP address.");} 64 | 65 | int x; 66 | for(x = 0; x < 4; x++){ 67 | buffers[x] = new JTextArea("", 1, 30); 68 | buffers[x].setEditable(false); 69 | buffers[x].setBackground(window.getBackground()); 70 | } 71 | 72 | c.add(addressLabel); 73 | c.add(ipTxt); 74 | c.add(buffers[0]); 75 | c.add(portLabel); 76 | portTxt.setText("5444"); 77 | c.add(portTxt); 78 | 79 | c.add(buffers[3]); 80 | 81 | c.add(clientPortLabel); 82 | clientPortTxt.setText("5555"); 83 | c.add(clientPortTxt); 84 | 85 | c.add(buffers[1]); 86 | c.add(connectButton); 87 | c.add(disconnectButton); 88 | c.add(buffers[2]); 89 | c.add(serverMessages); 90 | 91 | //c.add(shutdownButton); 92 | ipTxt.setSize(100, 20); 93 | window.setLocationRelativeTo(null); 94 | window.setVisible(true); 95 | window.setResizable(false); 96 | 97 | int port = Integer.parseInt(portTxt.getText()); 98 | int clientPort = Integer.parseInt(clientPortTxt.getText()); 99 | 100 | try{ 101 | InetAddress ip = InetAddress.getByName(ipTxt.getText()); 102 | runServer(port, clientPort, ip); 103 | }catch(UnknownHostException err){ 104 | serverMessages.setText("Error: Check that the ip you have entered is correct."); 105 | } 106 | } 107 | 108 | 109 | private InetAddress getIpAddress() throws Exception 110 | { 111 | // this first line generally works on mac and windows 112 | InetAddress ip = InetAddress.getLocalHost(); 113 | 114 | // but on linux... 115 | if(ip.isLoopbackAddress()) 116 | { 117 | //loop trough all network interfaces 118 | Enumeration nets = NetworkInterface.getNetworkInterfaces(); 119 | for (NetworkInterface netint : Collections.list(nets)) 120 | { 121 | //loop through the ip address associated with the interface 122 | Enumeration inetAddresses = netint.getInetAddresses(); 123 | for (InetAddress inetAddress : Collections.list(inetAddresses)) { 124 | 125 | // if the address is no the loopback and is not ipv6 126 | if(!inetAddress.isLoopbackAddress() && !inetAddress.toString().contains(":")) 127 | return inetAddress; 128 | } 129 | } 130 | } 131 | 132 | return ip; 133 | } 134 | 135 | public void actionPerformed(ActionEvent e){ 136 | Object src = e.getSource(); 137 | 138 | if(src instanceof JButton){ 139 | if((JButton)src == connectButton){ 140 | int port = Integer.parseInt(portTxt.getText()); 141 | int clientPort = Integer.parseInt(clientPortTxt.getText()); 142 | try{ 143 | InetAddress ip = InetAddress.getByName(ipTxt.getText()); 144 | runServer(port, clientPort, ip); 145 | }catch(UnknownHostException err){ 146 | serverMessages.setText("Error: Check that the ip you have entered is correct."); 147 | } 148 | } 149 | 150 | else if((JButton)src == disconnectButton){ 151 | closeServer(); 152 | setConnectButtonEnabled(true); 153 | } 154 | 155 | else if((JButton)src == shutdownButton){ 156 | closeServer(); 157 | shutdown(); 158 | System.exit(0); 159 | } 160 | } 161 | } 162 | 163 | public void runServer(int port, int listenerPort, InetAddress ip){ 164 | if(port < 65535){ 165 | server.setPort(port); 166 | server.setClientPort(listenerPort); 167 | server.setIP(ip); 168 | sThread = new Thread(server); 169 | sThread.start(); 170 | serverMessages.setText("Waiting for connection on " + ip); 171 | connectButton.setEnabled(false); 172 | }else{ 173 | serverMessages.setText("The port Number must be less than 65535"); 174 | connectButton.setEnabled(true); 175 | } 176 | } 177 | 178 | public void closeServer(){ 179 | server.shutdown(); 180 | setMessage("Disconnected"); 181 | } 182 | 183 | public void setMessage(String msg){ 184 | serverMessages.setText(msg); 185 | } 186 | 187 | public void setConnectButtonEnabled(boolean enable){ 188 | connectButton.setEnabled(enable); 189 | } 190 | 191 | private static void shutdown(){ 192 | String shutdownCommand; 193 | String operatingSystem = System.getProperty("os.name"); 194 | 195 | if ("Linux".equals(operatingSystem) || "Mac OS X".equals(operatingSystem)) { 196 | shutdownCommand = "shutdown -h now"; 197 | } 198 | else if ("Windows".equals(operatingSystem)) { 199 | shutdownCommand = "shutdown.exe -s -t 0"; 200 | } 201 | else { 202 | shutdownCommand = "null"; 203 | } 204 | 205 | Runtime runtime = Runtime.getRuntime(); 206 | try { 207 | Process proc = runtime.exec(shutdownCommand); 208 | } catch (IOException e) { 209 | // TODO Auto-generated catch block 210 | e.printStackTrace(); 211 | } 212 | } 213 | 214 | 215 | public static void main(String[] args){ 216 | new ServerWindow(); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/messages/Constants.java: -------------------------------------------------------------------------------- 1 | package messages; 2 | 3 | import java.awt.Point; 4 | 5 | public class Constants { 6 | 7 | public static final char LEFTMOUSEDOWN = 'a'; 8 | public static final char LEFTMOUSEUP = 'b'; 9 | 10 | public static final char RIGHTMOUSEDOWN = 'c'; 11 | public static final char RIGHTMOUSEUP = 'd'; 12 | 13 | public static final char LEFTCLICK = 'e'; 14 | 15 | public static final char SCROLLUP = 'h'; 16 | public static final char SCROLLDOWN = 'i'; 17 | 18 | public static final char KEYBOARD = 'k'; 19 | public static final char KEYCODE = 'l'; 20 | 21 | public static final char DELIMITER = '/'; 22 | 23 | public static final char MOVEMOUSE = 'p'; 24 | 25 | public static final char REQUESTIMAGE = 'I'; 26 | 27 | /* 28 | * Returns a string in the format that can be laster parsed 29 | * format: MOVEMOUSEintxDELIMITERinty 30 | * ex: p5/6 31 | */ 32 | public static String createMoveMouseMessage(float x, float y){ 33 | int intx = Math.round(x); 34 | int inty = Math.round(y); 35 | return ""+MOVEMOUSE + intx + DELIMITER + inty; 36 | } 37 | 38 | public static Point parseMoveMouseMessage(String message){ 39 | String[] tokens = message.substring(1).split(""+Constants.DELIMITER ); 40 | return new Point(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1])); 41 | } 42 | } 43 | --------------------------------------------------------------------------------