Full Mouse Control, código

Editado: Para que no cargue toda la entrada cada vez que se entra al blog he añadido la opción leer mas.

Para situarse leer antes: Full Mouse Control, caracteristicas , en él explico en que consiste el código que veréis a continuación de manera que se entiendan las caracteristicas implementadas sin tener en cuanta como se hace a nivel de código.

El tronco principal de la implementación de la interfaz es:


/**
 * Modo para un control global del raton y el teclado
 * @author Alberto Poblacion Navarro
 *
 */
 class FullMouseMode implements AbstractInputHandler {

 /* (non-Javadoc)
 * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, android.view.KeyEvent)
 */

 @Override
 public boolean onKeyDown(int keyCode, KeyEvent evt) {
 if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){
 KeyEvent camera = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_CAMERA);
 vncCanvas.processLocalKeyEvent(KeyEvent.KEYCODE_CAMERA, camera);
 vncCanvas.processPointerEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_DOWN, vncCanvas.mouseX,vncCanvas.mouseY, 0), false);           
 }
 else{

 defaultKeyDownHandler( keyCode, evt);
 }

 return true;
 }

 /* (non-Javadoc)
 * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, android.view.KeyEvent)
 */
 @Override
 public boolean onKeyUp(int keyCode, KeyEvent evt) {

 if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){
 vncCanvas.processPointerEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_UP, vncCanvas.mouseX,vncCanvas.mouseY, 0), false);
 KeyEvent camera = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_CAMERA);
 vncCanvas.processLocalKeyEvent(KeyEvent.KEYCODE_CAMERA, camera);       
 }
 else{

 defaultKeyUpHandler( keyCode, evt);
 }
 return true;
 }

 /* (non-Javadoc)
 * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent)
 */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 return fullmousetouch(event);
 }
 /* (non-Javadoc)
 * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent)
 */
 @Override
 public boolean onTrackballEvent(MotionEvent evt) {
 return false;
 }
 /* (non-Javadoc)
 * @see android.androidVNC.AbstractInputHandler#handlerDescription()
 */
 @Override
 public CharSequence getHandlerDescription() {
 return getResources().getText(R.string.input_mode_full_mouse);
 }

 /* (non-Javadoc)
 * @see android.androidVNC.AbstractInputHandler#getName()
 */
 @Override
 public String getName() {
 return "FULL MOUSE";
 }

 }

En esta parte del codigo podemos ver los métodos mas importantes de la interfaz. Caracteristicas a destacar

  • Como expliqué anteriormente para hacer funcionar el click derecho basta con tener pulsada el botón de la cámara, he sido incapaz de hacerlo funcionar en el emulador, solución: creo un evento de teclado como que se ha pulsado la cámara cuando quiero mandar el click derecho, es decir cuando pulso/suelto el botón central.
  • Si se pulsa una tecla que no sea la central se trata como un evento de teclado normal y se manda a la funcion: defaultKeyDownHandler( keyCode, evt); / defaultKeyUpHandler( keyCode, evt);
  • Si existe algún evento de ratón se llama a la función fullmousetouch(event);. Donde se trataran los tres tipos de eventos: pulsar, soltar, y mover.

Quiero aclarar que todas estas funciones están dentro de un contexto, son partes de un programa mucho mayor, simplemente voy a mostrar aquí mi código y las partes  necesarias para explicarlo. Cuando me acostumbre a la forja de redIris, subiré el código completo y lo notificaré en el blog (espero tardar lo menos posible).

Nota: vncCanvas es la capa encargada de dibujar en la pantalla todo lo que vemos. Mas información aqui.


boolean defaultKeyDownHandler( int keyCode, KeyEvent evt)
 {
 if ( vncCanvas.processLocalKeyEvent(keyCode, evt))
 return true;
 return super.onKeyDown(keyCode, evt);
 }

 boolean defaultKeyUpHandler( int keyCode, KeyEvent evt)
 {
 if ( vncCanvas.processLocalKeyEvent(keyCode, evt))
 return true;
 return super.onKeyUp(keyCode, evt);
 }

A continuación muestro, como manejo los eventos de ratón para el click, el arrastre y el movimiento:


 private Date down; //Momento de la pulsacion
 private Date up; // Momento en el que se suelta la pulsacion
 private final int click = 100; //Tiempo en milisegundos para saber que se trata de un click
 private final int drag = 500; //Tiempo en milisegundos para saber si hay que arrastrar en vez de mover

 CountDownTimer timer; //Temporizador para saber si se trata de un click o para arrastrar

 boolean fullmousetouch( MotionEvent event)
 {
 switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN:
 down=new Date();//Momento de la pulsacion
 final MotionEvent evento = MotionEvent.obtain(event);
 final Context contex_=this;

 //Si es una pulsacion larga: modo de arrastre.
 timer = new CountDownTimer(drag, 10){

 public void onTick(long millisUntilFinished) {
 }

 public void onFinish() {

 Toast.makeText(contex_, "Dragging Mode", Toast.LENGTH_SHORT).show();
 evento.setAction(MotionEvent.ACTION_DOWN);
 // Adjust coordinates for Android notification bar.
 evento.offsetLocation(0, -1f * vncCanvas.getTop());
 // Adjust coordinates for panning position.
 evento.offsetLocation(absoluteXPosition, absoluteYPosition);
 vncCanvas.processPointerEvent(evento, true);
 }
 }.start();

 break;
 case MotionEvent.ACTION_MOVE:

 Move(event);
 //Cancelas el timeout para que no entre en el modo de arrastre
 timer.cancel();

 break;
 case MotionEvent.ACTION_UP:
 up=new Date(); //Para conocer la duracion de la pulsacion
 timer.cancel();
 //Si es una pulsacion rapida: click de raton
 if (up.getTime() - down.getTime() < click)
 {
 //Mandas el gesto del click complento, cuando pulsas y cuando sueltas la tecla
 event.setAction(MotionEvent.ACTION_DOWN);
 // Adjust coordinates for Android notification bar.
 event.offsetLocation(0, -1f * vncCanvas.getTop());
 // Adjust coordinates for panning position.
 event.offsetLocation(absoluteXPosition, absoluteYPosition);
 //Mandas el click completo: pulsas y sueltas
 vncCanvas.processPointerEvent(event, true);
 event.setAction(MotionEvent.ACTION_UP);
 vncCanvas.processPointerEvent(event, true);
 break;
 }
 //Si no ha sido un click del raton mandas que se levantado la tecla simplemente
 event.setAction(MotionEvent.ACTION_UP);
 // Adjust coordinates for Android notification bar.
 event.offsetLocation(0, -1f * vncCanvas.getTop());
 // Adjust coordinates for panning position.
 event.offsetLocation(absoluteXPosition, absoluteYPosition);
 vncCanvas.processPointerEvent(event, true);
 break;

 }
 return true;       
 }

 final int border = 20; //Distancia entre el cursor y el borde para que se desplace la pantalla
 /**
 * Mueve la parte de escritorio en la que nos encontramos si estamos a una distancia menor de "border" de un extremo
 * @param event
 * @author Alberto Poblacion Navarro
 */
 private void Move(MotionEvent event) {
 //Obtienes las cordenadas donde tienes el cursor

 float curX = event.getX();
 float curY = event.getY();
 int scrollX =0;
 int scrollY =0;

 //Si pulsamos el raton a menos distancia de "border" de uno de los extremos, configuramos la posicion que
 //debemos mover la imagen
 Display display=getWindowManager().getDefaultDisplay();
 if (curX  > (display.getWidth()-border)) scrollX +=border;
 if (curX  < border) scrollX -=border;
 if (curY  > (display.getHeight()-border)) scrollY +=border;
 if (curY  < border) scrollY -=border;

 absoluteXPosition += scrollX;
 absoluteYPosition += scrollY;
 //Comprobamos los margenes superior e izquierdo
 if(absoluteXPosition < 0){
 scrollX=0;
 absoluteXPosition=0;
 }
 if(absoluteYPosition < 0){
 scrollY=0;
 absoluteYPosition=0;
 }
 //Comprobamos los márgenes derecho y inferior
 if (absoluteXPosition + vncCanvas.getWidth()> vncCanvas.getImageWidth()){
 scrollX=0;
 absoluteXPosition-=border;
 }
 if (absoluteYPosition + vncCanvas.getHeight() > vncCanvas.getImageHeight()){
 scrollY=0;
 absoluteYPosition-=border;
 }
 //Movemos la posicion del escritorio
 vncCanvas.scrollBy(scrollX, scrollY);

 event.offsetLocation(0, -1f * vncCanvas.getTop());
 event.offsetLocation(absoluteXPosition, absoluteYPosition);
 vncCanvas.processPointerEvent(event, false);

 }
}

Bueno esto es una buena parte de código además bastante difícil de entender si no sabes de donde vienen muchas cosas, por ello voy a explicar brevemente lo que he hecho.

Aspectos a destacar de la función fullmousetouch:

  • El cometido principal de esta función es diferenciar las distintas acciones del ratón y mandarlos a procesar según su comportamiento.
  • Cuando realizo una pulsación en la pantalla y lo suelto tomo los tiempos en lo que han sucedido dichos eventos.
  • Cada vez que realizo una pulsación (sin movimiento), se pone en marcha una cuenta atrás, que se cancelará si se suelta la pulsación o existe movimiento.
  • Si el tiempo que ha pasado entre que pulso y suelto es muy corto quiere decir que se produce un click. Para que el ordenador remoto sepa que se ha realizado un click de ratón, se le manda el evento como que se ha pulsado el botón izquierdo del ratón y como que se ha soltado de manera casi inmediata.
  • Si no se cancela la cuenta atrás y termina con normalidad se entra en un modo denominado “Dragging mode”. En este modo si se mueve el cursor se hará como si tuvieramos el botón izuqierdo del ratón pusaldo ya que mandamos el evento del ratón “down” pero no mandamos el “up” hasta que no se vuelva a soltar la pulsación.

Aspectos importantes de la funcion Move:

  • El principal objetivo de dicha función es no limitar el espacio donde podemos mover el raton.
  • Si movemos el ratón hacia uno de los bordes esta función mandará a procesar el movimiento del raton y si se acerca a una distancia X del borde desplazará el escritorio en esa direccion.
  • La idea principal esta sacada de la funcion “private void pan(MotionEvent event)”, del código original.

Esto es a grandes rasgos la primera modificacion que he realizado para el cliente VNC de Android. Espero subir cuanto antes el código a la forja para todos aquellos que les interese investigar el código puedan hacerlo. Por cierto el código no esta ni mucho menos en su versión definitiva si encontrais algún error o alguna cosa que pueda mejorarse estoy totalmente a vuestra disposición.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: