Làm cách nào để thực hiện thao tác kéo (dựa trên tọa độ chuột X, Y) trên Android bằng AccessService?


39

Tôi muốn biết cách thực hiện thao tác kéo trên Android dựa trên tọa độ chuột X, Y? xem xét như hai ví dụ đơn giản, Team Viewer / QuickSupport vẽ "mẫu mật khẩu" trên điện thoại thông minh từ xa và Pen of Windows Paint tương ứng.

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Tất cả những gì tôi có thể làm là mô phỏng cảm ứng (có dispatchGesture()và cũng có AccessibilityNodeInfo.ACTION_CLICK).

Tôi tìm thấy các liên kết liên quan này, nhưng không biết liệu chúng có hữu ích không:

Dưới đây là mã làm việc của tôi được sử dụng để gửi tọa độ chuột (bên trong PictureBoxđiều khiển) đến điện thoại từ xa và mô phỏng cảm ứng.

Ứng dụng 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));
    }
}

Biên tập:

Lần thử cuối cùng của tôi là "màn hình vuốt" bằng cách sử dụng tọa độ chuột (Ứng dụng biểu mẫu C # Windows) và thói quen tùy chỉnh Android (có tham chiếu đến mã "màn hình vuốt" được liên kết ở trên), tương ứng:

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

Dịch vụ truy cập 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);
}

}

tạo ra kết quả sau (nhưng vẫn không thể vẽ "mật khẩu mẫu" như TeamViewer chẳng hạn). Nhưng giống như đã nói trên bình luận bên dưới, tôi nghĩ rằng với một cách tiếp cận tương tự, điều này có thể đạt được bằng cách sử dụng cử chỉ Tiếp tục . Bất kỳ đề xuất theo hướng này sẽ được hoan nghênh.

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Chỉnh sửa 2:

Chắc chắn, giải pháp là tiếp tục cử chỉ như đã nói trên Chỉnh sửa trước đó .

Và dưới đây là một mã cố định được cho là tôi tìm thấy ở đây =>

Dịch vụ truy cập 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);

Sau đó, nghi ngờ của tôi là: làm thế nào để gửi tọa độ chuột chính xác cho mã ở trên, về cách có thể thực hiện kéo đến bất kỳ hướng nào? Một số ý tưởng?


Chỉnh sửa 3:

Tôi đã tìm thấy hai thói quen được sử dụng để thực hiện kéo, nhưng chúng đang sử dụng UiAutomation + injectInputEvent(). AFAIK, tiêm sự kiện chỉ hoạt động trong một ứng dụng hệ thống như đã nói ở đâyở đây và tôi không muốn nó.

Đây là thói quen được tìm thấy:

Sau đó, để đạt được mục tiêu của mình, tôi nghĩ rằng thói quen thứ 2 được sử dụng nhiều hơn (theo logic, không bao gồm nội dung sự kiện) với mã được hiển thị trên Chỉnh sửa 2 và gửi tất cả các điểm pictureBox1_MouseDownpictureBox1_MouseMove(Ứng dụng Biểu mẫu Windows C) tương ứng để điền Point[]động và pictureBox1_MouseUpgửi cmd để thực hiện các thường trình và sử dụng mảng này điền. Nếu bạn có ý tưởng về thói quen thứ 1, hãy cho tôi biết: D.

Nếu sau khi đọc Chỉnh sửa này, bạn có một giải pháp khả thi, vui lòng cho tôi xem câu trả lời, trong khi tôi sẽ thử và kiểm tra ý tưởng này.


1
TeamViewer không sử dụng khung khả năng truy cập, rất có thể. Họ có thỏa thuận đặc biệt với các nhà sản xuất thiết bị, đó là lý do tại sao sản phẩm của họ không có sẵn cho tất cả các thiết bị.
CommonsWare

@CommonsWare cảm ơn bạn. Nhưng tôi nghĩ rằng đó StrokeDescription.continueStroke()có thể là một giải pháp có thể. Xem phần Cử chỉ tiếp tục ở đây .
BrowJr

2
Về aproach đầu tiên của bạn. pictureBox1_MouseDownkhông được gửi tọa độ. Nó chỉ nên lưu trữ các tọa độ ban đầu, và sau đó pictureBox1_MouseUpbạn gửi chúng, bởi vì điều đó đánh dấu sự kết thúc của chuyển động chuột
Greggz

Câu trả lời:


1

Dưới đây là một ví dụ về giải pháp dựa trên Chỉnh sửa 3 câu hỏi.


Ứng dụng 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);
}

dịch vụ 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 AccessibilityService" MyAccessibilityService.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);
        }
    }
}

0

Bạn đã thử sử dụng kịch bản AutoIt chưa?

Bạn có thể lưu tọa độ trong các cửa sổ / màn hình cụ thể. Bạn có thể giữ mouseclick nhấn trong khi vẽ mẫu.

Tôi cũng có một số ví dụ mã / script cho bạn nếu bạn muốn chúng!


BIÊN TẬP:

Theo hướng dẫn này bạn có thể sử dụng Auto-IT trên C #.

Thực hiện theo các bước sau:

  1. Cài đặt tự động-CNTT
  2. Thêm Auto-IT làm tham chiếu trong trình quản lý tham chiếu (AutoItX3.dll)
  3. Sau đó, nhập thư viện mà bạn đã thêm: Using AutoItX3Lib;
  4. Tạo đối tượng AutoItX3 mới gọi là 'auto': AutoItX3 auto = new AutoItX3();
  5. Bây giờ bạn có thể thực thi các lệnh Auto It.

Đây là ví dụ đầy đủ để thực hiện một mouseclick:

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


Với AutoIt Window Info Tool bạn có thể kiểm tra tọa độ bạn muốn sử dụng.

Xin lưu ý rằng có sự khác biệt giữa các chế độ tọa độ chuột:

ví dụ: auto.AutoItSetOption("MouseCoordMode", 1)sẽ sử dụng tọa độ màn hình tuyệt đối. Xem nguồn tại đây .


Để giữ mouseclick xuống, bạn có thể kiểm tra Chức năng MouseDown


1
Điều này không giúp được gì. Đề xuất của bạn chính xác là những gì Ứng dụng Biểu mẫu C # Windows của tôi đã thực hiện.
BrowJr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.