前言

有感于各路大神对STF细节功能的挖掘:
STF 框架之 minicap 工具
[STF 系列] 无痛接入基于 LDAP 的单点登录
发现除了minicap之外,对于STF的设备管理的触摸功能,他们用的是类似的依赖工具,叫minitouch,Git地址:https://github.com/openstf/minitouch

minitouch介绍

跟minicap一样,minitouch也是用NDK开发的,跟minicap使用方法类似,不过它只要上传一个minitouch文件就可以了。对应的文件路径树跟minicap一样就不重复介绍(不过它只需要对应不同的CPU的ABI,而不需要对应SDK版本)。实际测试这个触摸操作和minicap一样,实时性很高没什么卡顿。

使用概述

minitouch的output信息

之后进行触摸操作的时候我发现,部分设备是可以准确的执行到正确的坐标,而部分设备坐标存在巨大的偏差。于是有仔细的看下文档,仔细看了minitouch的output部分信息:

When you first open a connection to the socket, you'll get some protocol metadata which you'll need need to read from the socket. Other than that there will be no responses of any kind.

首先,当socket连接建立的时候,socket的首次output信息会返回minitouch对应的头信息,我尝试用一段C#代码对它进行读取

static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1111));
byte[] chunk = new byte[1024];
socket.Receive(chunk);
Console.WriteLine(System.Text.Encoding.Default.GetString(chunk));
Console.ReadLine();
}

执行后可以看到返回的数据为:

官方文档中对它的描述分别为:

这边要重点说的是max-x和max-y,这边返回的值有可能和你的设备的真实大小并不是一样的,比如我用三星GalaxyNote10.1的平板调试,读取到的max-x和max-y分别为4095x4095,而设备的实际分辨率为1600x2560。
所以我注意看了下官方文档有写了:

It's also very important to note that the maximum X and Y coordinates may, but usually do not, match the display size. You'll need to work out a good way to map display coordinates to touch coordinates if required, possibly by using percentages for screen coordinates.
文档里有说到通常不匹配显示大小,你需要自己用一个方法来映射坐标,建议是用百分比来显示

于是我做了个实验,对设备发送了

d 0 2048 2048 50\n      
c\n

然后在设备上发现,设备被点击的坐标是800,1280,果然分别是真实坐标的一半。
那么就是说我们在实际应用中需要给设备分别换算出真实设备大小和minitouch映射大小的宽度和高度的百分比参数,来进行正确的坐标映射。
需要对设备进行操作的时候,将要点击的坐标除以这个百分比就可以得到要给设备发送的正确坐标。
用C#做了个简单的实现:

public class MiniTouchStream
{
private String IP = "127.0.0.1";
private int PORT = 1111;
private Socket socket;
private Banner banner = new Banner();
private AndroidDevice device;

public Banner Banner
{
get
{
return banner;
}
}

public MiniTouchStream(AndroidDevice device)
{
this.device = device;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Parse(IP), PORT));
ParseBanner(socket);
}

private void ParseBanner(Socket socket)
{
byte[] chunk = new byte[64];
socket.Receive(chunk);
string[] result = Encoding.Default.GetString(chunk).Split(new char[2] { '\n', ' ' }).ToArray();
banner.Version = Convert.ToInt32(result[1]);
banner.MaxContacts = Convert.ToInt32(result[3]);
banner.MaxX = Convert.ToInt32(result[4]);
banner.MaxY = Convert.ToInt32(result[5]);
banner.MaxPressure = Convert.ToInt32(result[6]);
banner.Pid = Convert.ToInt32(result[8]);
banner.PercentX = (double)device.Width / banner.MaxX;
banner.PercentY = (double)device.Height / banner.MaxY;
}

public void TouchDown(Point downpoint)
{
Point realpoint = PointConvert(downpoint);
ExecuteTouch(string.Format("d 0 {0} {1} 50\n", realpoint.X.ToString(), realpoint.Y.ToString()));
}

public void TouchUp()
{
ExecuteTouch(string.Format("u 0\n"));
}

public void TouchMove(Point movepoint)
{
Point realpoint = PointConvert(movepoint);
ExecuteTouch(string.Format("m 0 {0} {1} 50\n", realpoint.X.ToString(), realpoint.Y.ToString()));
}

public void ExecuteTouch(string touchcommand)
{
byte[] inbuff = Encoding.ASCII.GetBytes(touchcommand);
socket.Send(inbuff);
string ccommand = "c\n";
inbuff = Encoding.ASCII.GetBytes(ccommand);
socket.Send(inbuff);
}

private Point PointConvert(Point point)
{
Point realpoint = new Point((int)(point.X / banner.PercentX) * device.Scale, (int)(point.Y / banner.PercentY) * device.Scale);
return realpoint;
}
}

最后贴个结合minicap和minitouch简单写的一个小demo,
C#demo
第一次启动可能会稍微慢点,耐心等下


↙↙↙阅读原文可查看相关链接,并与作者交流