Files
MagnetismHeroes/tools/android/send-composition-touch.ps1
T

32 lines
2.8 KiB
PowerShell

param([Parameter(Mandatory)][int[]]$Contacts, [int]$Port=8554)
$ErrorActionPreference='Stop'
if ($Contacts.Count -eq 0 -or $Contacts.Count % 4 -ne 0) { throw 'Contacts must contain repeated x,y,id,pressure quadruples.' }
[AppContext]::SetSwitch('System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport', $true)
$discovery=Get-ChildItem -LiteralPath (Join-Path $env:LOCALAPPDATA 'Temp/avd/running') -Filter 'pid_*.ini' | Sort-Object LastWriteTime -Descending | Select-Object -First 1
$tokenLine=Get-Content -LiteralPath $discovery.FullName | Where-Object { $_ -match '^grpc.token=' } | Select-Object -First 1
if (!$tokenLine) { throw 'Authenticated emulator discovery is required; tokens are never logged.' }
function Varint([int]$Value) {
[uint32]$number=$Value; $bytes=[Collections.Generic.List[byte]]::new()
while ($number -ge 128) { $bytes.Add([byte](($number -band 127) -bor 128)); $number=$number -shr 7 }
$bytes.Add([byte]$number); return ,$bytes.ToArray()
}
$message=[Collections.Generic.List[byte]]::new()
for ($offset=0; $offset -lt $Contacts.Count; $offset+=4) {
# AVD touch injection uses portrait physical coordinates even when the app is landscape-left.
$fields=@((1080-$Contacts[$offset+1]),$Contacts[$offset],$Contacts[$offset+2],$Contacts[$offset+3])
$touch=[Collections.Generic.List[byte]]::new()
for ($field=0; $field -lt 4; $field++) { $touch.Add([byte](8*($field+1))); $touch.AddRange([byte[]](Varint $fields[$field])) }
$message.Add(10); $message.AddRange([byte[]](Varint $touch.Count)); $message.AddRange($touch.ToArray())
}
$frame=[byte[]]::new($message.Count+5); $frame[1]=($message.Count -shr 24) -band 255; $frame[2]=($message.Count -shr 16) -band 255
$frame[3]=($message.Count -shr 8) -band 255; $frame[4]=$message.Count -band 255; $message.ToArray().CopyTo($frame,5)
$client=[Net.Http.HttpClient]::new(); $request=[Net.Http.HttpRequestMessage]::new([Net.Http.HttpMethod]::Post,"http://127.0.0.1:$Port/android.emulation.control.EmulatorController/sendTouch")
$request.Version=[Version]::new(2,0); $request.VersionPolicy=[Net.Http.HttpVersionPolicy]::RequestVersionExact
$request.Headers.Add('TE','trailers'); $request.Headers.Authorization=[Net.Http.Headers.AuthenticationHeaderValue]::new('Bearer',$tokenLine.Substring('grpc.token='.Length))
$request.Content=[Net.Http.ByteArrayContent]::new($frame); $request.Content.Headers.ContentType=[Net.Http.Headers.MediaTypeHeaderValue]::new('application/grpc')
try {
$response=$client.SendAsync($request).GetAwaiter().GetResult(); $response.EnsureSuccessStatusCode() | Out-Null
$status=if ($response.TrailingHeaders.Contains('grpc-status')) { ($response.TrailingHeaders.GetValues('grpc-status') -join '') } else { '0' }
if ($status -ne '0') { throw "Emulator sendTouch grpc-status=$status" }
} finally { $request.Dispose(); $client.Dispose() }