package com.iiordanov.bVNC.input;
import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.MotionEvent;
import com.iiordanov.android.bc.BCFactory;
import com.iiordanov.bVNC.RemoteCanvas;
import com.iiordanov.bVNC.RemoteCanvasActivity;
import com.iiordanov.bVNC.*;
import com.iiordanov.freebVNC.*;
import com.iiordanov.aRDP.*;
import com.iiordanov.freeaRDP.*;
import com.iiordanov.aSPICE.*;
import com.iiordanov.freeaSPICE.*;
public class SimulatedTouchpadInputHandler extends AbstractGestureInputHandler {
static final String TAG = "SimulatedTouchpadInputHandler";
public static final String TOUCHPAD_MODE = "TOUCHPAD_MODE";
float sensitivity = 0;
boolean acceleration = false;
/**
* @param c
*/
public SimulatedTouchpadInputHandler(RemoteCanvasActivity va, RemoteCanvas v, boolean slowScrolling) {
super(va, v, slowScrolling);
acceleration = activity.getAccelerationEnabled();
sensitivity = activity.getSensitivity();
}
/*
* (non-Javadoc)
*
* @see com.iiordanov.bVNC.AbstractInputHandler#getHandlerDescription()
*/
@Override
public CharSequence getHandlerDescription() {
return canvas.getResources().getString(R.string.input_mode_touchpad_description);
}
/*
* (non-Javadoc)
*
* @see com.iiordanov.bVNC.AbstractInputHandler#getName()
*/
@Override
public String getName() {
return TOUCHPAD_MODE;
}
/*
* (non-Javadoc)
*
* @see com.iiordanov.bVNC.RemoteCanvasActivity.ZoomInputHandler#onKeyDown(int,
* android.view.KeyEvent)
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent evt) {
return keyHandler.onKeyDown(keyCode, evt);
}
/*
* (non-Javadoc)
*
* @see com.iiordanov.bVNC.RemoteCanvasActivity.ZoomInputHandler#onKeyUp(int,
* android.view.KeyEvent)
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent evt) {
return keyHandler.onKeyUp(keyCode, evt);
}
/*
* (non-Javadoc)
*
* @see com.iiordanov.bVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent)
*/
@Override
public boolean onTrackballEvent(MotionEvent evt) {
return trackballMouse(evt);
}
/*
* (non-Javadoc)
*
* @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent,
* android.view.MotionEvent, float, float)
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
RemotePointer p = canvas.getPointer();
final int action = e2.getActionMasked();
final int meta = e2.getMetaState();
// TODO: This is a workaround for Android 4.2
boolean twoFingers = false;
if (e1 != null)
twoFingers = (e1.getPointerCount() > 1);
if (e2 != null)
twoFingers = twoFingers || (e2.getPointerCount() > 1);
// onScroll called while scaling/swiping gesture is in effect. We ignore the event and pretend it was
// consumed. This prevents the mouse pointer from flailing around while we are scaling.
// Also, if one releases one finger slightly earlier than the other when scaling, it causes Android
// to stick a spiteful onScroll with a MASSIVE delta here.
// This would cause the mouse pointer to jump to another place suddenly.
// Hence, we ignore onScroll after scaling until we lift all pointers up.
if (twoFingers||inSwiping||inScaling||scalingJustFinished)
return true;
activity.showZoomer(true);
// If the gesture has just began, then don't allow a big delta to prevent
// pointer jumps at the start of scrolling.
if (!inScrolling) {
inScrolling = true;
distanceX = sign(distanceX);
distanceY = sign(distanceY);
distXQueue.clear();
distYQueue.clear();
}
distXQueue.add(distanceX);
distYQueue.add(distanceY);
// Only after the first two events have arrived do we start using distanceX and Y
// In order to effectively discard the last two events (which are typically unreliable
// because of the finger lifting off).
if (distXQueue.size() > 2) {
distanceX = distXQueue.poll();
distanceY = distYQueue.poll();
} else {
return true;
}
// Make distanceX/Y display density independent.
distanceX = sensitivity * distanceX / displayDensity;
distanceY = sensitivity * distanceY / displayDensity;
// Compute the absolute new mouse position on the remote site.
int newRemoteX = (int) (p.getX() + getDelta(-distanceX));
int newRemoteY = (int) (p.getY() + getDelta(-distanceY));
p.processPointerEvent(newRemoteX, newRemoteY, action, meta, false, false, false, false, 0);
canvas.panToMouse();
return true;
}
/*
* (non-Javadoc)
*
* @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent)
*/
@Override
public boolean onDown(MotionEvent e) {
activity.stopPanner();
return true;
}
protected int getX (MotionEvent e) {
RemotePointer p = canvas.getPointer();
if (dragMode || rightDragMode || middleDragMode) {
float distanceX = e.getX() - dragX;
dragX = e.getX();
// Compute the absolute new X coordinate on the remote site.
return (int) (p.getX() + getDelta(distanceX));
}
dragX = e.getX();
return p.getX();
}
protected int getY (MotionEvent e) {
RemotePointer p = canvas.getPointer();
if (dragMode || rightDragMode || middleDragMode) {
float distanceY = e.getY() - dragY;
dragY = e.getY();
// Compute the absolute new Y coordinate on the remote site.
return (int) (p.getY() + getDelta(distanceY));
}
dragY = e.getY();
return p.getY();
}
private float getDelta(float distance) {
// Compute the relative movement offset on the remote screen.
float delta = (float) (distance * Math.cbrt(canvas.getScale()));
return fineCtrlScale(delta);
}
/**
* Scale down delta when it is small. This will allow finer control
* when user is making a small movement on touch screen.
* Scale up delta when delta is big. This allows fast mouse movement when
* user is flinging.
* @param deltaX
* @return
*/
private float fineCtrlScale(float delta) {
float sign = sign(delta);
delta = Math.abs(delta);
if (delta <= 15) {
delta *= 0.75;
} else if (acceleration && delta <= 70 ) {
delta *= delta/20;
} else if (acceleration) {
delta *= 4.5;
}
return sign * delta;
}
}