AccessibilityServiceを使用してAndroidで(X、Yマウス座標に基づいて)ドラッグを実行するにはどうすればよいですか?


39

X、Yマウス座標に基づいてAndroidでドラッグを実行する方法を知りたいですか?2つの単純な例として、チームビューア/ QuickSupportがそれぞれリモートのスマートフォンと「ペンオブウィンドウズペイント」で「パスワードパターン」を描画するとします。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

私が作ることができるすべてはタッチをシミュレートすることです(dispatchGesture()そしてまたAccessibilityNodeInfo.ACTION_CLICK)。

これらの関連リンクを見つけましたが、それらが役立つかどうかはわかりません。

以下は、(PictureBox制御内の)マウス座標をリモート電話に送信し、タッチをシミュレートするために使用する私の作業コードです。

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

編集:

私の最後の試みは、それぞれマウス座標(C#Windowsフォームアプリケーション)とカスタムandroidルーチン(上記の「スワイプ画面」のコードを参照)を使用した「スワイプ画面」でした。

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

}

次の結果が生成されます(ただし、たとえばTeamViewerのような「パターンパスワード」を描画することはできません)。しかし、以下のコメントで述べたように、同様のアプローチでこれはおそらく継続ジェスチャーを使用して達成できると思います。この方向での提案は歓迎されます。

ここに画像の説明を入力してください

ここに画像の説明を入力してください


編集2:

間違いなく、解決策は以前のEditで述べたようなジェスチャーを継続することです。

そして、以下は私がここで見つけた仮定の固定コードです =>

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

次に、私の疑問は、上記のコードのマウス座標をどのように正しく送信するか、どの方向にもドラッグを実行できる方法ですか?アイデアは?


編集3:

ドラッグの実行に使用される2つのルーチンを見つけましたが、それらはUiAutomation + を使用していinjectInputEvent()ます。AFAIK、イベントの注入は、ここここで言っようなシステムアプリでのみ機能し、私はそれを望んでいません。

これは見つかったルーチンです:

次に、私の目標を達成するために、編集2に示されたコードで(ロジックに従って、イベントインジェクションを除く)2番目のルーチンを使用する方が適切であると考え、動的に、pictureBox1_MouseDownおよびpictureBox1_MouseMove(C#Windowsフォームアプリケーション)のすべてのポイントをそれぞれ送信しますPoint[]pictureBox1_MouseUp送信cmdを実行してルーチンを実行し、この配列を埋めて使用します。あなたが最初のルーチンにアイデアを持っているなら、私に知らせてください:D。

この編集を読んだ後、考えられる解決策がある場合は、答えを教えてください。このアイデアをテストしてみます。


1
TeamViewerは、おそらくアクセシビリティフレームワークを使用していません。彼らはデバイスメーカーと特別な契約を結んでいるため、製品がすべてのデバイスで利用できるわけではありません。
CommonsWare、

@CommonsWareありがとうございます。しかし、私はそれStrokeDescription.continueStroke()がありそうな解決策になることができると思います。セクションを参照してください続きジェスチャーを ここに
BrowJr

2
あなたの最初のアプローチについて。pictureBox1_MouseDown座標を送信してはなりません。pictureBox1_MouseUpマウスの動きの終わりを示すので、最初の座標のみを保存してから送信します
Greggz

回答:


1

質問の編集3に基づくソリューションの例を次に示します。


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

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

AutoItスクリプトを使用しようとしましたか?

特定のウィンドウ/画面内の座標を保存できます。パターンを描く間、マウスクリックを押したままにすることができます。

また、必要に応じて、サンプルコード/スクリプトも用意しています。


編集:

このチュートリアルによると、C#でAuto-ITを使用できます。

次の手順を実行します:

  1. Auto-ITをインストールする
  2. 参照マネージャー(AutoItX3.dll)で参照としてAuto-ITを追加する
  3. 次に、追加したライブラリをインポートします。 Using AutoItX3Lib;
  4. 「auto」という新しいAutoItX3オブジェクトを作成します。 AutoItX3 auto = new AutoItX3();
  5. これでAuto Itコマンドを実行できます。

これは、マウスクリックを実行するための完全な例です。

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


ではAutoIt Window Info Tool、あなたが使用したい座標を確認することができます。

マウス座標モードには違いがあることに注意してください。

例:auto.AutoItSetOption("MouseCoordMode", 1)絶対スクリーン座標を使用します。ここでソースを参照してください。


マウスクリックを押し続けると、MouseDown関数を確認できます


1
これは役に立たなかった。あなたの提案は、まさに私のC#Windowsフォームアプリケーションが既に作成していることです。
BrowJr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.