package com.iiordanov.bVNC.input;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.iiordanov.bVNC.RfbConnectable;
import com.iiordanov.bVNC.RemoteCanvas;
public class RemoteVncPointer extends RemotePointer {
private static final String TAG = "RemotePointer";
public static final int MOUSE_BUTTON_NONE = 0;
public static final int MOUSE_BUTTON_LEFT = 1;
public static final int MOUSE_BUTTON_MIDDLE = 2;
public static final int MOUSE_BUTTON_RIGHT = 4;
public static final int MOUSE_BUTTON_SCROLL_UP = 8;
public static final int MOUSE_BUTTON_SCROLL_DOWN = 16;
public static final int MOUSE_BUTTON_SCROLL_LEFT = 32;
public static final int MOUSE_BUTTON_SCROLL_RIGHT = 64;
public MouseScrollRunnable scrollRunnable;
public RemoteVncPointer (RfbConnectable r, RemoteCanvas v, Handler h) {
super(r,v,h);
scrollRunnable = new MouseScrollRunnable();
}
public int getX() {
return mouseX;
}
public int getY() {
return mouseY;
}
public void setX(int newX) {
mouseX = newX;
}
public void setY(int newY) {
mouseY = newY;
}
/**
* Warp the mouse to x, y in the RFB coordinates
*
* @param x
* @param y
*/
public void warpMouse(int x, int y)
{
vncCanvas.invalidateMousePosition();
mouseX=x;
mouseY=y;
vncCanvas.invalidateMousePosition();
//android.util.Log.i(TAG, "warp mouse to " + x + "," + y);
rfb.writePointerEvent(x, y, 0, MOUSE_BUTTON_NONE);
}
public void mouseFollowPan()
{
if (vncCanvas.getMouseFollowPan())
{
int scrollx = vncCanvas.getAbsoluteX();
int scrolly = vncCanvas.getAbsoluteY();
int width = vncCanvas.getVisibleWidth();
int height = vncCanvas.getVisibleHeight();
//Log.i(TAG,"scrollx " + scrollx + " scrolly " + scrolly + " mouseX " + mouseX +" Y " + mouseY + " w " + width + " h " + height);
if (mouseX < scrollx || mouseX >= scrollx + width || mouseY < scrolly || mouseY >= scrolly + height) {
warpMouse(scrollx + width/2, scrolly + height / 2);
}
}
}
/**
* Moves the scroll while the volume key is held down
*
* @author Michael A. MacDonald
*/
public class MouseScrollRunnable implements Runnable
{
int delay = 100;
public int scrollButton = 0;
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if (rfb != null && rfb.isInNormalProtocol()) {
rfb.writePointerEvent(mouseX, mouseY, 0, scrollButton);
rfb.writePointerEvent(mouseX, mouseY, 0, 0);
handler.postDelayed(this, delay);
}
}
}
public boolean handleHardwareButtons(int keyCode, KeyEvent evt, int combinedMetastate) {
boolean down = (evt.getAction() == KeyEvent.ACTION_DOWN) ||
(evt.getAction() == KeyEvent.ACTION_MULTIPLE);
int mouseChange = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ? RemoteVncPointer.MOUSE_BUTTON_SCROLL_DOWN : RemoteVncPointer.MOUSE_BUTTON_SCROLL_UP;
if (shouldBeRightClick (evt)) {
if (down)
pointerMask = RemoteVncPointer.MOUSE_BUTTON_RIGHT;
else
pointerMask = 0;
rfb.writePointerEvent(getX(), getY(), combinedMetastate, pointerMask);
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
if (evt.getAction() == KeyEvent.ACTION_DOWN) {
// If not auto-repeat
if (scrollRunnable.scrollButton != mouseChange) {
pointerMask |= mouseChange;
scrollRunnable.scrollButton = mouseChange;
handler.postDelayed(scrollRunnable, 200);
}
} else {
handler.removeCallbacks(scrollRunnable);
scrollRunnable.scrollButton = 0;
pointerMask &= ~mouseChange;
}
rfb.writePointerEvent(getX(), getY(), combinedMetastate, pointerMask);
return true;
}
return false;
}
/**
* Overloaded processPointerEvent method which supports mouse scroll button.
* @param evt motion event; x and y must already have been converted from screen coordinates
* to remote frame buffer coordinates.
* @param downEvent True if "mouse button" (touch or trackball button) is down when this happens
* @param useRightButton If true, event is interpreted as happening with right mouse button
* @param useMiddleButton If true, event is interpreted as click happening with middle mouse button
* @param useScrollButton If true, event is interpreted as click happening with mouse scroll button
* @param direction Indicates the direction of the scroll event: 0 for up, 1 for down, 2 for left, 3 for right.
* @return true if event was actually sent
*/
public boolean processPointerEvent(MotionEvent evt, boolean downEvent,
boolean useRightButton, boolean useMiddleButton, boolean useScrollButton, int direction) {
return processPointerEvent((int)evt.getX(),(int)evt.getY(), evt.getActionMasked(),
evt.getMetaState(), downEvent, useRightButton, useMiddleButton, useScrollButton, direction);
}
/**
* Overloaded processPointerEvent method which supports middle mouse button.
* @param evt motion event; x and y must already have been converted from screen coordinates
* to remote frame buffer coordinates.
* @param downEvent True if "mouse button" (touch or trackball button) is down when this happens
* @param useRightButton If true, event is interpreted as happening with right mouse button
* @param useMiddleButton If true, event is interpreted as click happening with middle mouse button
* @return true if event was actually sent
*/
public boolean processPointerEvent(MotionEvent evt, boolean downEvent,
boolean useRightButton, boolean useMiddleButton) {
return processPointerEvent((int)evt.getX(),(int)evt.getY(), evt.getActionMasked(),
evt.getMetaState(), downEvent, useRightButton, useMiddleButton, false, -1);
}
/**
* Convert a motion event to a format suitable for sending over the wire
* @param evt motion event; x and y must already have been converted from screen coordinates
* to remote frame buffer coordinates.
* @param downEvent True if "mouse button" (touch or trackball button) is down when this happens
* @param useRightButton If true, event is interpreted as happening with right mouse button
* @return true if event was actually sent
*/
public boolean processPointerEvent(MotionEvent evt, boolean downEvent, boolean useRightButton) {
return processPointerEvent((int)evt.getX(),(int)evt.getY(), evt.getAction(),
evt.getMetaState(), downEvent, useRightButton, false, false, -1);
}
/**
* Overloaded processPointerEvent method which supports right mouse button.
* @param evt motion event; x and y must already have been converted from screen coordinates
* to remote frame buffer coordinates.
* @param downEvent True if "mouse button" (touch or trackball button) is down when this happens
* @param useRightButton If true, event is interpreted as happening with right mouse button
* @return true if event was actually sent
*/
public boolean processPointerEvent(int x, int y, int action, int modifiers, boolean mouseIsDown, boolean useRightButton) {
return processPointerEvent(x, y, action, modifiers, mouseIsDown, useRightButton, false, false, -1);
}
public boolean processPointerEvent(int x, int y, int action, int modifiers, boolean mouseIsDown, boolean useRightButton,
boolean useMiddleButton, boolean useScrollButton, int direction) {
if (rfb != null && rfb.isInNormalProtocol()) {
if (mouseIsDown && useRightButton) {
//Log.i(TAG,"Right mouse button mask set");
pointerMask = MOUSE_BUTTON_RIGHT;
} else if (mouseIsDown && useMiddleButton) {
//Log.i(TAG,"Middle mouse button mask set");
pointerMask = MOUSE_BUTTON_MIDDLE;
} else if (mouseIsDown && useScrollButton) {
//Log.d(TAG, "Sending a Mouse Scroll event: " + direction);
if ( direction == 0 ) {
pointerMask = MOUSE_BUTTON_SCROLL_UP;
} else if ( direction == 1 ) {
pointerMask = MOUSE_BUTTON_SCROLL_DOWN;
} else if ( direction == 2 ) {
pointerMask = MOUSE_BUTTON_SCROLL_LEFT;
} else if ( direction == 3 ) {
pointerMask = MOUSE_BUTTON_SCROLL_RIGHT;
}
} else if (mouseIsDown && (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE)) {
//Log.i(TAG,"Left mouse button mask set");
pointerMask = MOUSE_BUTTON_LEFT;
} else {
//Log.i(TAG,"Mouse button mask cleared");
// If none of the conditions are satisfied, clear the pointer mask.
pointerMask = 0;
}
vncCanvas.invalidateMousePosition();
mouseX = x;
mouseY = y;
if ( mouseX < 0) mouseX=0;
else if ( mouseX >= rfb.framebufferWidth()) mouseX = rfb.framebufferWidth() - 1;
if ( mouseY < 0) mouseY=0;
else if ( mouseY >= rfb.framebufferHeight()) mouseY = rfb.framebufferHeight() - 1;
vncCanvas.invalidateMousePosition();
rfb.writePointerEvent(mouseX, mouseY, modifiers|vncCanvas.getKeyboard().getMetaState(), pointerMask);
return true;
}
return false;
}
}