¿Quiero saber cómo realizar un arrastre en Android basado en las coordenadas X, Y del mouse? considere como dos ejemplos simples, el Team Viewer / QuickSupport dibujando el "patrón de contraseña" en el teléfono inteligente remoto y el Pen of Windows Paint, respectivamente.
Todo lo que puedo hacer es simular el tacto (con dispatchGesture()
y también AccessibilityNodeInfo.ACTION_CLICK
).
Encontré estos enlaces relevantes, pero no sé si pueden ser útiles:
A continuación se muestra mi código de trabajo que se utiliza para enviar las coordenadas del mouse (dentro del PictureBox
control) al teléfono remoto y simular el tacto.
Aplicación de formularios de Windows:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
foreach (ListViewItem item in lvConnections.SelectedItems)
{
// Remote screen resolution
string[] tokens = item.SubItems[5].Text.Split('x'); // Ex: 1080x1920
int xClick = (e.X * int.Parse(tokens[0].ToString())) / (pictureBox1.Size.Width);
int yClick = (e.Y * int.Parse(tokens[1].ToString())) / (pictureBox1.Size.Height);
Client client = (Client)item.Tag;
if (e.Button == MouseButtons.Left)
client.sock.Send(Encoding.UTF8.GetBytes("TOUCH" + xClick + "<|>" + yClick + Environment.NewLine));
}
}
Editar:
Mi último intento fue una "pantalla de deslizamiento" utilizando las coordenadas del mouse (aplicación de formularios Windows Forms de C #) y una rutina personalizada de Android (con referencia al código de "pantalla de deslizar" vinculado anteriormente), respectivamente:
private Point mdownPoint = new Point();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
foreach (ListViewItem item in lvConnections.SelectedItems)
{
// Remote screen resolution
string[] tokens = item.SubItems[5].Text.Split('x'); // Ex: 1080x1920
Client client = (Client)item.Tag;
if (e.Button == MouseButtons.Left)
{
xClick = (e.X * int.Parse(tokens[0].ToString())) / (pictureBox1.Size.Width);
yClick = (e.Y * int.Parse(tokens[1].ToString())) / (pictureBox1.Size.Height);
// Saving start position:
mdownPoint.X = xClick;
mdownPoint.Y = yClick;
client.sock.Send(Encoding.UTF8.GetBytes("TOUCH" + xClick + "<|>" + yClick + Environment.NewLine));
}
}
}
private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
foreach (ListViewItem item in lvConnections.SelectedItems)
{
// Remote screen resolution
string[] tokens = item.SubItems[5].Text.Split('x'); // Ex: 1080x1920
Client client = (Client)item.Tag;
if (e.Button == MouseButtons.Left)
{
xClick = (e.X * int.Parse(tokens[0].ToString())) / (pictureBox1.Size.Width);
yClick = (e.Y * int.Parse(tokens[1].ToString())) / (pictureBox1.Size.Height);
client.sock.Send(Encoding.UTF8.GetBytes("MOUSESWIPESCREEN" + mdownPoint.X + "<|>" + mdownPoint.Y + "<|>" + xClick + "<|>" + yClick + Environment.NewLine));
}
}
}
Servicio de accesibilidad de Android :
public void Swipe(int x1, int y1, int x2, int y2, int time) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
System.out.println(" ======= Swipe =======");
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
Path path = new Path();
path.moveTo(x1, y1);
path.lineTo(x2, y2);
gestureBuilder.addStroke(new GestureDescription.StrokeDescription(path, 100, time));
dispatchGesture(gestureBuilder.build(), new GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {
System.out.println("SWIPE Gesture Completed :D");
super.onCompleted(gestureDescription);
}
}, null);
}
}
que produce el siguiente resultado (pero todavía no puede dibujar "contraseña de patrón" como TeamViewer, por ejemplo). Pero como se dice en el comentario a continuación, creo que con un enfoque similar, esto se puede lograr usando gestos continuos probablemente. Cualquier sugerencia en esta dirección será bienvenida.
Edición 2:
Definitivamente, la solución son los gestos continuos como se dijo en la edición anterior .
- Simulación del movimiento del joystick con AccessibilityService
- Por qué la función continueStroke no funciona
Y a continuación hay un supuesto código fijo que encontré aquí =>
Servicio de accesibilidad de Android:
// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down.
Path path = new Path();
path.moveTo(200,200);
path.lineTo(400,200);
final GestureDescription.StrokeDescription sd = new GestureDescription.StrokeDescription(path, 0, 500, true);
// The starting point of the second path must match
// the ending point of the first path.
Path path2 = new Path();
path2.moveTo(400,200);
path2.lineTo(400,400);
final GestureDescription.StrokeDescription sd2 = sd.continueStroke(path2, 0, 500, false); // 0.5 second
HongBaoService.mService.dispatchGesture(new GestureDescription.Builder().addStroke(sd).build(), new AccessibilityService.GestureResultCallback(){
@Override
public void onCompleted(GestureDescription gestureDescription){
super.onCompleted(gestureDescription);
HongBaoService.mService.dispatchGesture(new GestureDescription.Builder().addStroke(sd2).build(),null,null);
}
@Override
public void onCancelled(GestureDescription gestureDescription){
super.onCancelled(gestureDescription);
}
},null);
Entonces, mi duda es: ¿cómo enviar correctamente las coordenadas del mouse para el código anterior, de la forma en que puede realizar el arrastre en cualquier dirección? ¿Alguna idea?
Edición 3:
Encontré dos rutinas que se usan para realizar el arrastre, pero están usando UiAutomation + injectInputEvent()
. AFAIK, la inyección de eventos funciona solo en una aplicación del sistema como se dice aquí y aquí y no la quiero.
Estas son las rutinas encontradas:
- deslizamiento público booleano (int downX, int downY, int upX, int upY, int steps, boolean drag)
- deslizamiento público booleano (segmentos de punto [], segmentos int)
Luego, para lograr mi objetivo, creo que la segunda rutina es más apropiada para usar (siguiendo la lógica, excluyendo la inyección de eventos) con el código mostrado en Edit 2 y enviando todos los puntos de pictureBox1_MouseDown
y pictureBox1_MouseMove
(C # Windows Forms Application) respectivamente para llenar Point[]
dinámicamente y al pictureBox1_MouseUp
enviar cmd para ejecutar la rutina y usar esta matriz llena. Si tiene una idea para la primera rutina, avíseme: D.
Si después de leer esta edición tiene una posible solución, muéstreme una respuesta, por favor, mientras que intentaré probar esta idea.
StrokeDescription.continueStroke()
puede ser una solución probable. Consulte la sección Gestos continuos aquí .
pictureBox1_MouseDown
No debe enviar las coordenadas. Solo debe almacenar las coordenadas iniciales, y luego pictureBox1_MouseUp
enviarlas, porque eso marca el final del movimiento del mouse