AzurLaneAutoScript icon indicating copy to clipboard operation
AzurLaneAutoScript copied to clipboard

不知道能不能支持在 Windows Subsystem for Android™️ 上使用

Open railzy opened this issue 4 years ago • 21 comments

现在大部分的游戏模拟器都无法兼容 windows 开启 hyper-v 功能,有些好用的新功能为了跑模拟器用不了,感觉挺不方便的。 现在 Windows Subsystem for Android™️ 开始逐渐测试,我试了一下感觉性能也不错,希望可以找到方法使脚本支持在上面使用,以后就可以抛弃模拟器了。 ~bluestacks5 hyper-v版性能还不错,可以先用着,不过要修改下设置否则跑脚本会黑屏卡住~

分辨率解决方法: 每次重启WSA都要运行下面的adb命令,将默认分辨率设为1280x720再开启游戏,保证分辨率正确

adb shell wm size 1280x720

现在的问题是脚本现有的截图方法都无法从WSA获取截图,无法识别游戏界面

找到类似的问题 https://github.com/ninthDevilHAUNSTER/ArknightsAutoHelper/issues/268#issuecomment-949618025

WSA 目前没有实现 AOSP screencap 需要的接口,无法进行截图。

可能的解决方案:

  1. 在 ADB shell 里用 app_process 载入 java 代码调用系统 framework 获取 view 的截图 👈需要写一堆 Java;
  2. 使用 Windows.Graphics.Capture 获取窗口的 DXGI Surface,并且复制回 CPU 👈需要写一堆 COM;
  3. 等微软修好 screencap 🙃

现在遇到的问题是 Windows Subsystem for Android™️ 好像不支持手动指定分辨率并固定, 程序分辨率是跟随窗口大小变化的,同时脚本检测的分辨率始终是默认分辨率,不会检测碧蓝航线窗口实时的分辨率

2021-10-21 12:36:26.417 | INFO | <<< EMULATOR SAVED >>>
2021-10-21 12:36:26.494 | INFO | [Package_name] com.YoStarJP.AzurLane
2021-10-21 12:36:26.940 | INFO | [Screen_size] 800x1280
2021-10-21 12:36:26.941 | WARNING | Not supported screen size: 800x1280
2021-10-21 12:36:26.941 | WARNING | Alas requires 1280x720
2021-10-21 12:36:26.941 | INFO | <<< SCRIPT END >>>

railzy avatar Oct 21 '21 04:10 railzy

可以试试调用 win32api 设置窗口分辨率 再看看能不能固定窗口大小

LmeSzinc avatar Oct 21 '21 05:10 LmeSzinc

更新: 发现 Windows Subsystem for Android™️ 设置了默认分辨率(即脚本检查的 Screen_size )为 Override size: 800x1280 解决方法为使用adb 连接,输入

adb shell wm size 1280x720

即可将默认分辨率修改为 1280x720,程序重启时会默认使用此分辨率,脚本检查 screen_size 通过

每次完全重启 Windows Subsystem for Android™️ 都会将 Override size 重置回 800x1280,因此脚本运行前要先运行一次adb shell wm size 1280x720保证分辨率正确

同时需要注意的是 Screen_size 和程序分辨率不是绑定的,和手机上的多窗口模式一样,程序分辨率随窗口大小改变,因此程序启动后调整窗口会导致脚本运行出现错误

railzy avatar Oct 21 '21 06:10 railzy

还有一个问题是,看起来 Windows Subsystem for Android™️ 所有打开了窗口的程序都不是后台运行的,所以不清楚当前应用是如何确定的,以及截取屏幕会返回哪个程序的图像,脚本运行是否会影响其它安卓程序的正常使用

现在日服还在维护,没有办法验证脚本实际运行情况

railzy avatar Oct 21 '21 07:10 railzy

更新: 尝试使用aScreenCap、 ADB、 uiautomator2方法都无法获取 Windows Subsystem for Android™️ 内应用的截图,手动输入adb命令同样无法获取截图,因此脚本无法使用。

railzy avatar Oct 21 '21 09:10 railzy

看群友尝试,也是卡在这了 原因是,ADB 截图是全黑的

15:51:33.673 | CRITICAL | Received pure black screenshots from emulator, color: [0. 0. 0.]
15:51:33.673 | CRITICAL | Screenshot method `ADB` may not work on emulator `127.0.0.1:58526`
15:51:33.673 | CRITICAL | Please use other screenshot methods

1ZA90YC7$6L~L)BQ_G)F33Q

LmeSzinc avatar Oct 21 '21 10:10 LmeSzinc

尝试使用 pywin32,无法获取窗口图片

import win32con, win32gui, win32ui
from PIL import Image

# 找到窗口
hWnd = win32gui.FindWindow(None,"アズールレーン") 

#获取句柄窗口的大小信息
left, top, right, bot = win32gui.GetWindowRect(hWnd)

width = right - left
height = bot - top

#返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
hWndDC = win32gui.GetWindowDC(hWnd)

#创建设备描述表
mfcDC = win32ui.CreateDCFromHandle(hWndDC)

#创建内存设备描述表
saveDC = mfcDC.CreateCompatibleDC()

#创建位图对象准备保存图片
saveBitMap = win32ui.CreateBitmap()

#为bitmap开辟存储空间
saveBitMap.CreateCompatibleBitmap(mfcDC,width,height)

#将截图保存到saveBitMap中
saveDC.SelectObject(saveBitMap)

#保存bitmap到内存设备描述表
saveDC.BitBlt((0,0), (width,height), mfcDC, (0, 0), win32con.SRCCOPY)

# PIL保存
###获取位图信息
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)

###生成图像
im_PIL = Image.frombuffer('RGB',(bmpinfo['bmWidth'],bmpinfo['bmHeight']),bmpstr,'raw','BGRX',0,1)
im_PIL.save("im_PIL.png") #保存
im_PIL.show() #显示

尝试获取其它程序窗口图像时正常,但尝试获取 wsa 运行的 alas 窗口结果返回纯黑空图片

另外由于系统设定的在高 dpi 下的缩放,GetWindowRect 也无法获取到正确的分辨率,可能通过 win32api 获取截图的方法不太可行

railzy avatar Nov 14 '21 13:11 railzy

围观,看大佬什么时候能有好办法

AssestinaR avatar Dec 06 '21 10:12 AssestinaR

尝试使用 pywin32,无法获取窗口图片

import win32con, win32gui, win32ui
from PIL import Image

# 找到窗口
hWnd = win32gui.FindWindow(None,"アズールレーン") 

#获取句柄窗口的大小信息
left, top, right, bot = win32gui.GetWindowRect(hWnd)

width = right - left
height = bot - top

#返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
hWndDC = win32gui.GetWindowDC(hWnd)

#创建设备描述表
mfcDC = win32ui.CreateDCFromHandle(hWndDC)

#创建内存设备描述表
saveDC = mfcDC.CreateCompatibleDC()

#创建位图对象准备保存图片
saveBitMap = win32ui.CreateBitmap()

#为bitmap开辟存储空间
saveBitMap.CreateCompatibleBitmap(mfcDC,width,height)

#将截图保存到saveBitMap中
saveDC.SelectObject(saveBitMap)

#保存bitmap到内存设备描述表
saveDC.BitBlt((0,0), (width,height), mfcDC, (0, 0), win32con.SRCCOPY)

# PIL保存
###获取位图信息
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)

###生成图像
im_PIL = Image.frombuffer('RGB',(bmpinfo['bmWidth'],bmpinfo['bmHeight']),bmpstr,'raw','BGRX',0,1)
im_PIL.save("im_PIL.png") #保存
im_PIL.show() #显示

尝试获取其它程序窗口图像时正常,但尝试获取 wsa 运行的 alas 窗口结果返回纯黑空图片

另外由于系统设定的在高 dpi 下的缩放,GetWindowRect 也无法获取到正确的分辨率,可能通过 win32api 获取截图的方法不太可行

通过获取desktop handle 截取桌面的方式还是可以的,不过需要保持应用运行在前台

wuzhendong01 avatar Dec 11 '21 09:12 wuzhendong01

更新:通过 adb shell dumpsys display | Select-String "mUniqueId=" 可以获取到应用窗口的id,然后使用 adb shell screencap -d 应用id 可以获取到截图

SaigyoujiYusora avatar Jan 15 '22 11:01 SaigyoujiYusora

更新:通过 adb shell dumpsys display | Select-String "mUniqueId=" 可以获取到应用窗口的id,然后使用 adb shell screencap -d 应用id 可以获取到截图

我这里试了一下没成功 wsa 版本 1.8.32836.0 使用独显

通过上面的命令得到 mUniqueId=virtual:com.microsoft.windows.systemapp:com.YoStarJP.AzurLane:1

尝试命令 adb shell screencap -p -d 1 /storage/emulated/0/Download/1.png ,得到 1

adb shell screencap -p -d virtual:com.microsoft.windows.systemapp:com.YoStarJP.AzurLane:1 /storage/emulated/0/Download/2.png 得到 2

railzy avatar Jan 15 '22 13:01 railzy

更新:通过 adb shell dumpsys display | Select-String "mUniqueId=" 可以获取到应用窗口的id,然后使用 adb shell screencap -d 应用id 可以获取到截图

我这里试了一下没成功 wsa 版本 1.8.32836.0 使用独显

通过上面的命令得到 mUniqueId=virtual:com.microsoft.windows.systemapp:com.YoStarJP.AzurLane:1

尝试命令 adb shell screencap -p -d 1 /storage/emulated/0/Download/1.png ,得到 1

adb shell screencap -p -d virtual:com.microsoft.windows.systemapp:com.YoStarJP.AzurLane:1 /storage/emulated/0/Download/2.png 得到 2

是否使用过如adb shell wm size 1280x720 -d 1一类的修改窗口大小指令 使用过的具体表现为对应应用显示画面冻结,用过了就不可以拿到截图了,要wm size reset -d 1之后才可以了 如果还是不行,可以试试手动拖一下窗口大小来刷新(

SaigyoujiYusora avatar Jan 15 '22 16:01 SaigyoujiYusora

image image

@echo off setlocal enabledelayedexpansion set /a a=0 for /l %%c in (1 1 100) do ( set /a a+=1 adb exec-out screencap -p -d 1 > !a!screen.png ) pause 使用上述批处理连续截图100张,有部分图片出现和你相同的情况 ps:在我发送此消息此消息的时候 又截不到图了,adb -s 127.0.0.1:58526 shell screencap -d 1 /sdcard/1.png | adb -s 127.0.0.1:58526 pull /sdcard/1.png ./依旧可以获取截图(但同样不稳定)

SaigyoujiYusora avatar Jan 15 '22 17:01 SaigyoujiYusora

是否使用过如adb shell wm size 1280x720 -d 1一类的修改窗口大小指令 使用过的具体表现为对应应用显示画面冻结,用过了就不可以拿到截图了,要wm size reset -d 1之后才可以了 如果还是不行,可以试试手动拖一下窗口大小来刷新(

使用adb shell wm size reset -d 1再手动拖动窗口终于能截图了,可能是以前的设置遗留了下来,但是确实现在截图很不稳定 不过分辨率又是一个问题了,现在wsa会记录应用窗口大小Physical size,在应用重启时使用,无法通过adb shell wm size 1280x720来指定分辨率

railzy avatar Jan 16 '22 02:01 railzy

大佬们加油!win11正式版也推出安卓子系统,体验已经很不错了,能刷游戏了

moehz avatar Feb 28 '22 02:02 moehz

尝试使用 pywin32,无法获取窗口图片

import win32con, win32gui, win32ui
from PIL import Image

# 找到窗口
hWnd = win32gui.FindWindow(None,"アズールレーン") 

#获取句柄窗口的大小信息
left, top, right, bot = win32gui.GetWindowRect(hWnd)

width = right - left
height = bot - top

#返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
hWndDC = win32gui.GetWindowDC(hWnd)

#创建设备描述表
mfcDC = win32ui.CreateDCFromHandle(hWndDC)

#创建内存设备描述表
saveDC = mfcDC.CreateCompatibleDC()

#创建位图对象准备保存图片
saveBitMap = win32ui.CreateBitmap()

#为bitmap开辟存储空间
saveBitMap.CreateCompatibleBitmap(mfcDC,width,height)

#将截图保存到saveBitMap中
saveDC.SelectObject(saveBitMap)

#保存bitmap到内存设备描述表
saveDC.BitBlt((0,0), (width,height), mfcDC, (0, 0), win32con.SRCCOPY)

# PIL保存
###获取位图信息
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)

###生成图像
im_PIL = Image.frombuffer('RGB',(bmpinfo['bmWidth'],bmpinfo['bmHeight']),bmpstr,'raw','BGRX',0,1)
im_PIL.save("im_PIL.png") #保存
im_PIL.show() #显示

尝试获取其它程序窗口图像时正常,但尝试获取 wsa 运行的 alas 窗口结果返回纯黑空图片

另外由于系统设定的在高 dpi 下的缩放,GetWindowRect 也无法获取到正确的分辨率,可能通过 win32api 获取截图的方法不太可行

saveDC.BitBlt((0,0), (width,height), mfcDC, (0, 0), win32con.SRCCOPY) 改为 windll.user32.PrintWindow(hWnd, saveDC.GetSafeHdc(), 2) 可以获取截图,应该是directx的问题。


p.s. 可以通过GetDpiForWindow获取DPI信息,然后通过MoveWindow配合调整窗口大小,最后用SendMessage来模拟点击,感觉可行; 最小化的问题或许无法解决,因为wsa设计上是最小化=应用后台

buding983 avatar Apr 11 '22 03:04 buding983

我这边截图出现的情况貌似也差不多 第一张是外面看到的,第二张是截图报错丢到log里的

image

2022-07-14_22-40-48-460528

WindyCloudCute avatar Jul 14 '22 14:07 WindyCloudCute

我尝试通过·python+adb的方式来截图 效果如下,部分黑屏现象我不确定是我电脑配置的问题还是调用adb的问题 image 代码如下

import os
import subprocess

os.system('adb connect 127.0.0.1:58526')
for i in range(100):
    out = subprocess.Popen('adb shell screencap -p',stdout=subprocess.PIPE)
    out = out.stdout.read().replace(b'\r\n', b'\n')

    with open(str(i)+".jpg","wb") as f:
        #fp = open("test.jpg","wb")
        f.write(out)
        f.close

gaozheng2001 avatar Jul 16 '22 00:07 gaozheng2001

目前我这边wsa的问题得到了基本的解决 已经能正常运行了 情况也基本稳定 解决方法是吧 wsa设为无边框窗口 并吧wsa窗口丢到屏幕0,0的位置然后大小调整为1280*720即可 截图方案aScreenCap_nc 控制方案 minitouch 控制使用的是QtScrcpy

WindyCloudCute avatar Jul 16 '22 05:07 WindyCloudCute

目前我这边wsa的问题得到了基本的解决 已经能正常运行了 情况也基本稳定 解决方法是吧 wsa设为无边框窗口 并吧wsa窗口丢到屏幕0,0的位置然后大小调整为1280*720即可 截图方案aScreenCap_nc 控制方案 minitouch 控制使用的是QtScrcpy

可以提交一个 PR 解决这个问题吗?检查wsa是否符合这些条件,如果不符合,自动帮助用户解决并继续运行,截图和控制方案也改成强制使用 aScreenCap_nc 和 minitouch

wsa设为无边框窗口 并吧wsa窗口丢到屏幕0,0的位置然后大小调整为1280*720即可

LmeSzinc avatar Jul 26 '22 14:07 LmeSzinc

我是用Win32API随便写的一个玩意弄的 代码的意思就是循环查找碧蓝航线名字的窗口找到之后直接把他弄成无边框然后丢到屏幕左上角 这一堆是C#的代码 👇

using System.Runtime.InteropServices;
const int GWL_STYLE = (-16);
const int WS_EX_WINDOWEDGE = 0x00000100;
const int WS_EX_DLGMODALFRAME = 0x00000001;
const int WS_CHILD = 0x40000000;
const int WS_BORDER = 0x00800000;
const int WS_DLGFRAME = 0x00400000;
const int WS_CAPTION = 0x00C00000;

Console.WriteLine("脚本开始运行");
while (true)
{
    IntPtr hWnd = FindWindow(null, "碧蓝航线");
    long windowdata = GetWindowLong(hWnd, GWL_STYLE);
    if (windowdata != 335609856 && windowdata != 0)
    {
        Console.WriteLine("窗口变动:" + windowdata);
        SetWindowLong(hWnd, GWL_STYLE, 335609856);
        MoveWindow(hWnd, 0, 0, 1280, 720, true); 
    }
    else { Console.WriteLine("窗口未变动"); }
    System.Threading.Thread.Sleep(1000);
}



[DllImport("User32.dll", EntryPoint = "FindWindow")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);


[DllImport("user32.dll", EntryPoint = "SetWindowText")]
static extern int SetWindowText(IntPtr hwnd, string lpString);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool BRePaint);

[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
static extern int GetWindowLong(IntPtr hWnd, int type);

[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
static extern int SetWindowLong(IntPtr hWnd, int type, int dwNewLong);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

WindyCloudCute avatar Jul 26 '22 14:07 WindyCloudCute

WSA 在 2204 后有变化,#1560 尝试增加了对新 WSA 的适配

LmeSzinc avatar Aug 27 '22 14:08 LmeSzinc

https://learn.microsoft.com/zh-cn/windows/android/wsa/

Microsoft 正在停止为适用于 Android™️ 的 Windows 子系统 (WSA) 提供支持。 自 2025 年 3 月 5 日起,将不再支持 Windows 上的 Amazon Appstore 以及依赖于 WSA 的所有应用程序和游戏。

SaarChaffee avatar Mar 21 '24 11:03 SaarChaffee

https://learn.microsoft.com/zh-cn/windows/android/wsa/

Microsoft 正在停止为适用于 Android™️ 的 Windows 子系统 (WSA) 提供支持。 自 2025 年 3 月 5 日起,将不再支持 Windows 上的 Amazon Appstore 以及依赖于 WSA 的所有应用程序和游戏。

辛苦了,微软这波操作真的完美符合“陛下为何先降”,笑死

moehz avatar Apr 03 '24 08:04 moehz