Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
479 additions
and
0 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
sikuli-script/src/main/java/org/sikuli/script/VNCNative.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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
223
sikuli-script/src/main/java/org/sikuli/script/VNCRobot.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
|
||
|
Oops, something went wrong.