Skip to content

Commit

Permalink
New VNCRobot files.
Browse files Browse the repository at this point in the history
  • Loading branch information
niknah committed Feb 3, 2014
1 parent a8f7e88 commit 82e2507
Show file tree
Hide file tree
Showing 4 changed files with 479 additions and 0 deletions.
27 changes: 27 additions & 0 deletions sikuli-script/src/main/java/org/sikuli/script/VNCNative.java
@@ -0,0 +1,27 @@

package org.sikuli.script;

import java.awt.Rectangle;
import java.io.IOException;
import com.wapmx.nativeutils.jniloader.NativeLoader;

public class VNCNative {
static {
try {
NativeLoader.loadLibrary("VNCNative");
} catch(IOException e){
e.printStackTrace();
}
}

public static native long rfbGetClient(int bitsPerSample, int samplesPerPixel, int bytesPerPixel);
public static native void rfbInitClient(long client,String[] args,String password);
public static native int WaitForMessage(long client,int usecs);
public static native boolean HandleRFBServerMessage(long client);
public static native void CopyScreenToData(long client, int[] data,int x,int y,int width,int height);
public static native int GetWidth(long client);
public static native int GetHeight(long client);
public static native boolean SendPointerEvent(long client, int x, int y, int buttonMask);
public static native boolean SendKeyEvent(long client, int key, boolean down);
}

223 changes: 223 additions & 0 deletions sikuli-script/src/main/java/org/sikuli/script/VNCRobot.java
@@ -0,0 +1,223 @@
/*
* Copyright 2010-2011, Sikuli.org
* Released under the MIT License.
*
*/
package org.sikuli.script;


import java.awt.Robot;
import java.awt.GraphicsDevice;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.event.KeyEvent;

public class VNCRobot implements IRobot{
final static int MAX_DELAY = 60000;
long client;
int x,y,buttons;

class VNCRobotLoop implements Runnable {
long client;

public VNCRobotLoop(long client) { this.client=client; }
public void run() {
while(true) {
if(VNCNative.WaitForMessage(client,50)<0)
break;
if(!VNCNative.HandleRFBServerMessage(client))
break;
}
}

public void NewLoop() {
(new Thread(this)).start();
}
}

public VNCRobot(String[] args,String password) {
x=0; y=0; buttons=0;
client=VNCNative.rfbGetClient(8,3,4);
VNCNative.rfbInitClient(client,args,password);
VNCRobotLoop loop=new VNCRobotLoop(client);
loop.NewLoop();
}

public GraphicsDevice getGraphicsDevice() { return null; }
public Rectangle getBounds() {
Rectangle rect=new Rectangle(
0,0,
VNCNative.GetWidth(client),
VNCNative.GetHeight(client)
);
return rect;
}


public void mouseMove(int x, int y) {
this.x=x;
this.y=y;
VNCNative.SendPointerEvent(client,x,y,this.buttons);
}
public void mousePress(int buttons) {
if((buttons&Button.LEFT)>0) this.buttons|=1;
if((buttons&Button.MIDDLE)>0) this.buttons|=2;
if((buttons&Button.RIGHT)>0) this.buttons|=4;
VNCNative.SendPointerEvent(client,x,y,this.buttons);
}
public void mouseRelease(int buttons) {
if((buttons&Button.LEFT)>0) this.buttons&=-1^1;
if((buttons&Button.MIDDLE)>0) this.buttons&=-1^2;
if((buttons&Button.RIGHT)>0) this.buttons&=-1^4;
VNCNative.SendPointerEvent(client,x,y,this.buttons);
}
public void keyPress(int c) {
VNCNative.SendKeyEvent(client,c,true);
}
public void keyRelease(int c) {
VNCNative.SendKeyEvent(client,c,false);
}
public void mouseWheel(int move) {
int wheelButton=move<0?8:16;
this.buttons|=wheelButton;
VNCNative.SendPointerEvent(client,x,y,this.buttons);
try {
Thread.sleep(20);
} catch(InterruptedException e) { e.printStackTrace(); }
this.buttons&=-1^wheelButton;
VNCNative.SendPointerEvent(client,x,y,this.buttons);
}
public void waitForIdle() {
}
public void delay(long msecs) {
try {
Thread.sleep(msecs);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public void setAutoDelay(int msecs) {
}

public void smoothMove(Location dest){
smoothMove(Env.getMouseLocation(), dest, (long)(Settings.MoveMouseDelay*1000L));
}


public void smoothMove(Location src, Location dest, long ms){
if(ms == 0){
mouseMove(dest.x, dest.y);
return;
}

Animator aniX = new TimeBasedAnimator(
new OutQuarticEase((float)src.x, (float)dest.x, ms));
Animator aniY = new TimeBasedAnimator(
new OutQuarticEase((float)src.y, (float)dest.y, ms));
while(aniX.running()){
float x = aniX.step();
float y = aniY.step();
mouseMove((int)x, (int)y);
delay(50);
}
}

public void dragDrop(Location start, Location end, int steps, long ms, int buttons){
mouseMove(start.x, start.y);
mousePress(buttons);
delay((int)(Settings.DelayAfterDrag*1000));
waitForIdle();
smoothMove(start, end, ms);
delay((int)(Settings.DelayBeforeDrop*1000));
mouseRelease(buttons);
waitForIdle();
}


public void delay(int ms){
try {
if(ms<0)
ms = 0;
while(ms>MAX_DELAY){
Thread.sleep(MAX_DELAY);
ms -= MAX_DELAY;
}
Thread.sleep(ms);
} catch(InterruptedException e) {
e.printStackTrace();
}
}

public ScreenImage captureScreen(Rectangle rect){
int sz=rect.width*rect.height;
int[] data=new int[sz];

VNCNative.CopyScreenToData(client,data,rect.x,rect.y,rect.width,rect.height);
BufferedImage img = new BufferedImage(rect.width,rect.height,BufferedImage.TYPE_INT_RGB);
DataBufferInt bufferBytes=new DataBufferInt(data,sz);
int bitMask[] = new int[]{0xff,0xff00,0xff0000};
SinglePixelPackedSampleModel sm=new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,rect.width,rect.height,bitMask);
img.setData(Raster.createRaster(sm,bufferBytes,null));
return new ScreenImage(rect,img);
}


public void pressModifiers(int modifiers){
if((modifiers & KeyModifier.SHIFT) != 0) keyPress(KeyEvent.VK_SHIFT);
if((modifiers & KeyModifier.CTRL) != 0) keyPress(KeyEvent.VK_CONTROL);
if((modifiers & KeyModifier.ALT) != 0) keyPress(KeyEvent.VK_ALT);
if((modifiers & KeyModifier.META) != 0){
if( Env.getOS() == OS.WINDOWS )
keyPress(KeyEvent.VK_WINDOWS);
else
keyPress(KeyEvent.VK_META);
}
}

public void releaseModifiers(int modifiers){
if((modifiers & KeyModifier.SHIFT) != 0) keyRelease(KeyEvent.VK_SHIFT);
if((modifiers & KeyModifier.CTRL) != 0) keyRelease(KeyEvent.VK_CONTROL);
if((modifiers & KeyModifier.ALT) != 0) keyRelease(KeyEvent.VK_ALT);
if((modifiers & KeyModifier.META) != 0){
if( Env.getOS() == OS.WINDOWS )
keyRelease(KeyEvent.VK_WINDOWS);
else
keyRelease(KeyEvent.VK_META);
}
}

protected void doType(KeyMode mode, int... keyCodes) {
if(mode==KeyMode.PRESS_ONLY){
for(int i=0;i<keyCodes.length;i++){
keyPress(keyCodes[i]);
}
}
else if(mode==KeyMode.RELEASE_ONLY){
for(int i=0;i<keyCodes.length;i++){
keyRelease(keyCodes[i]);
}
}
else{
for(int i=0;i<keyCodes.length;i++)
keyPress(keyCodes[i]);
for(int i=0;i<keyCodes.length;i++)
keyRelease(keyCodes[i]);
}
}

public void typeChar(char character, KeyMode mode) {
doType(mode, character);
}

public Object getDevice(){
return null;
}

}

// vim: set smartindent expandtab ts=3 sw=3:
141 changes: 141 additions & 0 deletions sikuli-script/src/main/native/VNCNative.c
@@ -0,0 +1,141 @@
#include "VNCNative.h"
#include <rfb/rfbclient.h>

/*
* Class: org_sikuli_script_VNCNative
* Method: rfbGetClient
* Signature: (III)J
*/
JNIEXPORT jlong JNICALL Java_org_sikuli_script_VNCNative_rfbGetClient
(JNIEnv *env, jclass cls, jint bitsPerSample, jint samplesPerPixel, jint bytesPerPixel) {
return (unsigned long long)rfbGetClient(bitsPerSample, samplesPerPixel, bytesPerPixel);
}



static char *currentPassword;
static char *GetCurrentPassword(struct _rfbClient *client) {
return currentPassword;
}

/*
* Class: org_sikuli_script_VNCNative
* Method: rfbInitClient
* Signature: (J[Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_org_sikuli_script_VNCNative_rfbInitClient
(JNIEnv *env, jclass cls, jlong client, jobjectArray args,jstring password) {
const char **cargs;
int c;

jint count = (*env)->GetArrayLength(env, args);
cargs=malloc(sizeof(cargs[0])*(count+1));
for(c=0; c<count;++c) {
jobject element = (*env)->GetObjectArrayElement(env,args,c);
cargs[c]=(*env)->GetStringUTFChars(env,element,0);
}
cargs[count]=NULL;

const char *nativeString;
if(password!=NULL) {
nativeString=(*env)->GetStringUTFChars(env,password,0);
currentPassword=malloc(strlen(nativeString));
strcpy(currentPassword,nativeString);
((rfbClient *)client)->GetPassword=GetCurrentPassword;
}
rfbInitClient((rfbClient *)client,&count,(char **)cargs);

if(password!=NULL)
(*env)->ReleaseStringUTFChars(env, password, nativeString);
for(c=0; c<count;++c) {
(*env)->ReleaseStringUTFChars(env,(*env)->GetObjectArrayElement(env,args,c),cargs[c]);
}
}

/*
* Class: org_sikuli_script_VNCNative
* Method: WaitForMessage
* Signature: (JI)I
*/
JNIEXPORT jint JNICALL Java_org_sikuli_script_VNCNative_WaitForMessage
(JNIEnv *env, jclass cls, jlong client, jint usecs) {
return WaitForMessage((rfbClient *)client,usecs);
}

/*
* Class: org_sikuli_script_VNCNative
* Method: HandleRFBServerMessage
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_org_sikuli_script_VNCNative_HandleRFBServerMessage
(JNIEnv *env, jclass cls, jlong client) {
HandleRFBServerMessage((rfbClient *)client);
}

/*
* Class: org_sikuli_script_VNCNative
* Method: CopyScreenToData
* Signature: (J[B)Z
*/
JNIEXPORT void JNICALL Java_org_sikuli_script_VNCNative_CopyScreenToData
(JNIEnv *env, jclass cls, jlong client, jintArray output,jint x,jint y,jint width,jint height) {
int outputUpto=0;
int outputLen=(*env)->GetArrayLength(env,output);
int frameWidth=((rfbClient *)client)->width;
int frameHeight=((rfbClient *)client)->height;
const int *frameBuffer=(int *) ((rfbClient *)client)->frameBuffer;
const int *frameBufferEnd=frameBuffer+(frameWidth*frameHeight);

frameBuffer+=x+(y*frameWidth);
while(outputUpto<outputLen && (frameBuffer+width*4)<frameBufferEnd) {
(*env)->SetIntArrayRegion( env,output,outputUpto,width,frameBuffer);
outputUpto+=width;
frameBuffer+=frameWidth;
}

}


/*
* Class: org_sikuli_script_VNCNative
* Method: GetWidth
* Signature: (J)Z
*/
JNIEXPORT jint JNICALL Java_org_sikuli_script_VNCNative_GetWidth
(JNIEnv *env, jclass cls, jlong client) {
return ((rfbClient *)client)->width;
}

/*
* Class: org_sikuli_script_VNCNative
* Method: GetHeight
* Signature: (J)Z
*/
JNIEXPORT jint JNICALL Java_org_sikuli_script_VNCNative_GetHeight
(JNIEnv *env, jclass cls, jlong client) {
return ((rfbClient *)client)->height;
}



/*
* Class: org_sikuli_script_VNCNative
* Method: SendPointerEvent
* Signature: (JIII)Z
*/
JNIEXPORT jboolean JNICALL Java_org_sikuli_script_VNCNative_SendPointerEvent
(JNIEnv *env, jclass cls, jlong client, jint x, jint y, jint buttons) {
SendPointerEvent((rfbClient *)client,x,y,buttons);
}

/*
* Class: org_sikuli_script_VNCNative
* Method: SendKeyEvent
* Signature: (JIZ)Z
*/
JNIEXPORT jboolean JNICALL Java_org_sikuli_script_VNCNative_SendKeyEvent
(JNIEnv *env, jclass cls, jlong client, jint c, jboolean down) {
SendKeyEvent((rfbClient *)client,c,down);
}


0 comments on commit 82e2507

Please sign in to comment.