Jak wykonać przeciąganie (oparte na współrzędnych myszy X, Y) na Androidzie za pomocą AccessibilityService?

39

Chcę wiedzieć, jak wykonać przeciąganie na Androidzie oparte na współrzędnych myszy X, Y? rozważ jako dwa proste przykłady, Team Viewer / QuickSupport rysujący odpowiednio „wzorzec hasła” na zdalnym smartfonie i piórze Windows Paint.

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Wszystko, co jestem w stanie zrobić, to symulacja dotyku (z dispatchGesture()i również AccessibilityNodeInfo.ACTION_CLICK).

Znalazłem te linki, ale nie wiem, czy mogą być przydatne:

Poniżej znajduje się mój działający kod, który służy do wysyłania współrzędnych myszy (wewnątrz PictureBoxsterowania) do zdalnego telefonu i symulowania dotyku.

Aplikacja 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));
    }
}

Edytować:

Moją ostatnią próbą było „przesunięcie ekranu” przy użyciu współrzędnych myszy (aplikacja C # Windows Forms) i niestandardowej procedury Androida (w odniesieniu do kodu „przesunięcia ekranu”, który znajduje się powyżej), odpowiednio:

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);
}

}

co daje następujący wynik (ale nadal nie jest w stanie narysować „hasła wzorcowego” takiego jak na przykład TeamViewer). Ale jak powiedziano w komentarzu poniżej, myślę, że przy podobnym podejściu można to osiągnąć prawdopodobnie za pomocą Gestów kontynuowanych . Wszelkie sugestie w tym kierunku będą mile widziane.

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj


Edycja 2:

Zdecydowanie rozwiązaniem są kontynuowane gesty, jak wspomniano w poprzedniej edycji .

Poniżej znajduje się przypuszczalny naprawiony kod, który znalazłem tutaj =>

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);

Wątpię zatem : jak poprawnie przesłać współrzędne myszy dla powyższego kodu, jak można przeciągać w dowolnym kierunku? Jakiś pomysł?


Edycja 3:

Znalazłem dwie procedury, które służą do przeciągania, ale używają UiAutomation + injectInputEvent(). AFAIK, wstrzyknięcie zdarzenia działa tylko w aplikacji systemowej, jak powiedziano tu i tutaj i nie chcę tego.

Oto znalezione procedury:

Następnie, aby osiągnąć mój cel, uważam, że druga procedura jest bardziej odpowiednia do użycia (zgodnie z logiką, z wyłączeniem wstrzykiwania zdarzeń) z kodem pokazanym w Edycji 2 i wysłania wszystkich punktów pictureBox1_MouseDowni pictureBox1_MouseMove(C # Windows Forms Application) odpowiednio do wypełnienia Point[]dynamicznego i przy pictureBox1_MouseUpwysyłaniu cmd, aby wykonać procedurę i użyć tej tablicy wypełnionej. Jeśli masz pomysł na pierwszą rutynę, daj mi znać: D.

Jeśli po przeczytaniu tej edycji masz możliwe rozwiązanie, pokaż mi odpowiedź, a ja spróbuję przetestować ten pomysł.

BrowJr
źródło
1
TeamViewer najprawdopodobniej nie korzysta ze struktury ułatwień dostępu. Mają specjalne oferty z producentami urządzeń, dlatego ich produkt nie jest dostępny dla wszystkich urządzeń.
CommonsWare
@CommonsWare dziękuję. Ale myślę, że StrokeDescription.continueStroke()może to być prawdopodobne rozwiązanie. Zobacz sekcję „ Gesty kontynuowane” tutaj .
BrowJr
2
Jeśli chodzi o twoje pierwsze podejście. pictureBox1_MouseDownnie wolno wysyłać współrzędnych. Powinien on przechowywać tylko początkowe współrzędne, a następnie pictureBox1_MouseUpje wysyłać, ponieważ oznacza to koniec ruchu myszy
Greggz,

Odpowiedzi:

1

Oto przykład rozwiązania opartego na Edycji 3 pytania.


Aplikacja C # Windows Froms „ formMain.cs ”:

using System.Net.Sockets;

private List<Point> lstPoints;

private void pictureBox1_MouseDown(object sender, MouseEventArgs e) 
{
    if (e.Button == MouseButtons.Left)
    {
        lstPoints = new List<Point>();
        lstPoints.Add(new Point(e.X, e.Y));
    }
}

private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        lstPoints.Add(new Point(e.X, e.Y));
    }
}

private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    lstPoints.Add(new Point(e.X, e.Y));

    StringBuilder sb = new StringBuilder();

    foreach (Point obj in lstPoints)
    {
        sb.Append(Convert.ToString(obj) + ":");
    }

    serverSocket.Send("MDRAWEVENT" + sb.ToString() + Environment.NewLine);
}

usługa Android „ SocketBackground.java ”:

import java.net.Socket;

String xline;

while (clientSocket.isConnected()) {

    BufferedReader xreader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));

    if (xreader.ready()) {

        while ((xline = xreader.readLine()) != null) {
                xline = xline.trim();

            if (xline != null && !xline.trim().isEmpty()) {

                if (xline.contains("MDRAWEVENT")) {

                    String coordinates = xline.replace("MDRAWEVENT", "");
                    String[] tokens = coordinates.split(Pattern.quote(":"));
                    Point[] moviments = new Point[tokens.length];

                    for (int i = 0; i < tokens.length; i++) {
                       String[] coordinates = tokens[i].replace("{", "").replace("}", "").split(",");

                       int x = Integer.parseInt(coordinates[0].split("=")[1]);
                       int y = Integer.parseInt(coordinates[1].split("=")[1]);

                       moviments[i] = new Point(x, y);
                    }

                    MyAccessibilityService.instance.mouseDraw(moviments, 2000);
                }
            }
        }
    }
}

Android AccessibilityServiceMyAccessibilityService.java ”:

public void mouseDraw(Point[] segments, int time) {
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

        Path path = new Path();
        path.moveTo(segments[0].x, segments[0].y);

        for (int i = 1; i < segments.length; i++) {

            path.lineTo(segments[i].x, segments[i].y);

            GestureDescription.StrokeDescription sd = new GestureDescription.StrokeDescription(path, 0, time);

            dispatchGesture(new GestureDescription.Builder().addStroke(sd).build(), new AccessibilityService.GestureResultCallback() {

                @Override
                public void onCompleted(GestureDescription gestureDescription) {
                    super.onCompleted(gestureDescription);
                }

                @Override
                public void onCancelled(GestureDescription gestureDescription) {
                    super.onCancelled(gestureDescription);
                }
            }, null);
        }
    }
}
BrowJr
źródło
0

Czy próbowałeś używać skryptów AutoIt ?

Możesz zapisać współrzędne w określonych oknach / ekranach. Możesz przytrzymać naciśnięty przycisk myszy podczas rysowania wzoru.

Mam też dla ciebie przykładowy kod / skrypty, jeśli chcesz!


EDYTOWAĆ:

Zgodnie z tym samouczkiem możesz używać Auto-IT na C #.

Wykonaj następujące kroki:

  1. Zainstaluj Auto-IT
  2. Dodaj Auto-IT jako odniesienie w menedżerze referencji (AutoItX3.dll)
  3. Następnie zaimportuj bibliotekę, którą dodałeś: Using AutoItX3Lib;
  4. Utwórz nowy obiekt AutoItX3 o nazwie „auto”: AutoItX3 auto = new AutoItX3();
  5. Możesz teraz wykonywać polecenia Auto It.

Oto kompletny przykład wykonania kliknięcia myszką:

Using AutoItX3Lib;
AutoItX3 auto = new AutoItX3();
auto.MouseClick("left", 78, 1133, 1, 35)


Za pomocą AutoIt Window Info Toolmożesz sprawdzić współrzędne, których chcesz użyć.

Uwaga: istnieją różnice między trybami współrzędnych myszy:

na przykład: auto.AutoItSetOption("MouseCoordMode", 1)użyje bezwzględnych współrzędnych ekranu. Zobacz źródło tutaj .


Aby przytrzymać przycisk myszy, możesz zaznaczyć funkcję MouseDown

JaFizz
źródło
1
To nie pomogło. Twoja sugestia jest dokładnie tym, co moja aplikacja C # Windows Form Application już tworzy.
BrowJr