Quero saber como executar um arrasto no Android com base nas coordenadas X, Y do mouse? considere como dois exemplos simples: o Team Viewer / QuickSupport desenha o "padrão de senha" no smartphone remoto e a Caneta do Windows Paint, respectivamente.
Tudo o que eu posso fazer é simular o toque (com dispatchGesture()
e também AccessibilityNodeInfo.ACTION_CLICK
).
Encontrei esses links relevantes, mas não sei se eles podem ser úteis:
Abaixo está o meu código de trabalho usado para enviar coordenadas do mouse (dentro de PictureBox
controle) para o telefone remoto e simular o toque.
Aplicativo Windows Forms:
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:
Minha última tentativa foi uma "tela de furto" usando as coordenadas do mouse (C # Windows Forms Application) e uma rotina android personalizada (com referência ao código da "tela de furto" vinculada acima), 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));
}
}
}
android AccessibilityService :
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 produz o seguinte resultado (mas ainda não é capaz de desenhar "senha padrão" como o TeamViewer, por exemplo). Mas, como dito no comentário abaixo, acho que com uma abordagem semelhante, isso pode ser alcançado usando gestos contínuos provavelmente. Todas as sugestões nessa direção serão bem-vindas.
Edição 2:
Definitivamente, a solução são gestos contínuos, como dito na edição anterior .
- Simulando o movimento do joystick usando o AccessibilityService
- Por que a função continueStroke não funciona
E abaixo está um suposto código fixo que eu encontrei aqui =>
android AccessibilityService:
// 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);
Então, minha dúvida é: como enviar corretamente as coordenadas do mouse para o código acima, do modo que pode ser executado em qualquer direção? Alguma idéia?
Edição 3:
Eu encontrei duas rotinas que são usadas para executar o arrasto, mas elas estão usando o UiAutomation + injectInputEvent()
. AFAIK, a injeção de evento funciona apenas em um aplicativo de sistema como o dito aqui e aqui e eu não quero isso.
Estas são as rotinas encontradas:
- furto público booleano (int downX, int downY, int upX, int upY, etapas int, arraste booleano)
- furto público booleano (segmentos [Point], int segmentSteps)
Então, para alcançar meu objetivo, acho que a 2ª rotina é mais apropriada para usar (seguindo a lógica, excluindo a injeção de eventos) com o código mostrado no Edit 2 e enviar todos os pontos pictureBox1_MouseDown
e pictureBox1_MouseMove
(C # Windows Forms Application), respectivamente, para preencherPoint[]
dinamicamente e ao pictureBox1_MouseUp
enviar cmd para executar a rotina e usar essa matriz preenchida. Se você tem uma idéia da 1ª rotina, me informe: D.
Se, depois de ler este Edit, você tiver uma solução possível, mostre-me uma resposta, por favor, enquanto tentarei testar essa idéia.
StrokeDescription.continueStroke()
pode ser uma solução provável. Veja a seção Gestos continuados aqui .
pictureBox1_MouseDown
não deve enviar as coordenadas. Ele deve armazenar apenas as coordenadas iniciais e, depois, pictureBox1_MouseUp
enviá-las, porque isso marca o fim do movimento do mouse.