diff --git a/README.html b/README.html new file mode 100644 index 0000000..e68e90c --- /dev/null +++ b/README.html @@ -0,0 +1,676 @@ + + + + + +README + +
+

VinXiangQi

一款基于深度学习(YOLOv5)的中国象棋连线工具

该程序当前阶段还缺少许多功能,希望有人能加入一起完善

软件/技术交流群:755655813

软件简介

0、界面介绍

image-20220711145322503

1、识别画面

image-20220711145437807

显示Yolo模型对画面的识别情况

2、识别结果

image-20220711145528668

显示目前局面的稳定识别结果以及引擎的走法,注意:该部分棋子可以点击,点击时会自动把对棋子的点击转发到被连线的游戏和软件中,方便对游戏中点击位置进行调试

3、引擎设置

image-20220711145715450

4、识别设置

image-20220711145734293

5、引擎思考输出

image-20220711145912807

6、引擎设置

image-20220711145946599

通过UCI或者UCCI协议获取到的关于引擎的设置选项

7、开局库设置

image-20220711150033775

选择是否使用云库和开局库

8、自动点击管理

image-20220711150109702

当连线设置中的自动点击被勾选时,软件会自动点击画面中保存模板的位置,可以实现自动续盘等功能。

使用方式:在右侧的画面中,点击需要框选的区域的左上和右下的点,确认无误后点击保存,即可保存自动点击的模板。

9、保存方案

image-20220711150256531

当使用 “寻找窗口句柄” 功能创建方案后,确定方案可用后,点击 “保存当前方案” 即可将当前方案保存下来下次使用。

需要注意的是,如果截图标题中包含有关当前对局或者网址的信息,可以将截图标题删去,保留截图类,可能方案会更通用。

1、创建方案或使用内置方案

方案是TXT格式的文件,储存在 程序根目录/Solutions 文件夹内,内容为:

  1. 用于截图的窗口类名或者标题

  2. 用于点击的子窗口类名或者标题(可留空,则截图和点击的为同一窗体)

    内置方案示例如下

    ./Solutions/JJ象棋_棋力评测/window.txt

    ./Solutions/天天象棋/window.txt

  3. 也可以点击寻找窗口句柄按钮,在点击按钮2秒内把鼠标移至目标窗口上方,来获取窗口句柄。

2、确认窗体缩放比

  1. 选中你想要使用的方案
  2. image-20220711143552442
  3. 根据左上角截图情况调整缩放比:如果截图显示不全,则增大缩放比;如果截图存在黑边,就减小缩放比,直到窗口完美覆盖图片。
  4. 关闭调试状态

3、前台与后台

image-20220711143729937

截图模式

后台截图:仅对窗口,而不是整个桌面进行截屏,在该模式下,连线的目标窗体可以被遮挡,不影响截图。

但需要注意的是,该模式并非通用方法,有的游戏和软件因为渲染方式的不同,并不能使用该方式截到图,这时调试状态显示的画面为黑色的。如果遇到这类软件,就需要勾选前台截图,使用截取屏幕的方式进行截图。

前台截图:通用模式,所有游戏和软件都可以使用,但是要求窗口不能被遮挡。

鼠标模式

后台鼠标:通过给目标窗口发送系统消息的方式进行鼠标操作,不是所有软件和游戏都能用。

该方式允许你在进行连线的时候鼠标同时操作别的事务,请优先选择该模式,如果遇到点击失败,则勾选前台鼠标模式。

前台鼠标:通用模式,所有游戏和软件都可以用,但是会占用鼠标,如果在连线点击下棋的过程中移动了鼠标,就有可能导致点击失败。

 

3、开始下棋

1.打开游戏中的对局

2.根据当前轮到我方或者对方,选择我方开始或是对方开始

3.这时连线应该已经自动开始了,如没有开始,则点击重新检测棋盘来刷新

image-20220711145322503

4、自动续盘

因为用户存在不同分辨率和不同缩放比,自动续盘需要点击的按钮需要用户自行截取

1. 点击 “自动点击管理”

image-20220705023407649

管理界面如下

image-20220705023516915

2. 在右侧图片上点击

第一次确定左上坐标,第二次确定右下坐标

image-20220705023551019

框好后有绿色框框指示

请注意:请务必在识别的范围内尽量减小框选范围,不要选择整个按钮,这样可以提升检测效率。

3. 保存图片

点击保存即可保存该自动点击图片

image-20220705023617339

4. 勾选自动点击

image-20220711150802910

启用自动点击后,即可自动点击保存截图中的按钮,进行自动续盘

异常情况

对于后台截图出现黑屏的窗体(如浏览器)可勾选前台截图,前台截图方式要求目标窗体前不能有遮挡。

对于不能点击的情况,可以勾选前台鼠标,该方式占用鼠标进行点击,为通用方法。

如使用过程中出现停止分析(持续识别模式时有概率出现),则点击重新检测棋盘来检测。

如果更多问题或者发现Bug,请加入软件/技术交流群:755655813,来反馈!

 

+ + \ No newline at end of file diff --git a/README.md b/README.md index 8458c35..8c5278d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,66 @@ # VinXiangQi -基于Yolov5的中国象棋连线工具 +一款基于深度学习(YOLOv5)的中国象棋连线工具 -模型训练集中天天象棋的样本较多,其他棋盘的识别效果不一定好。 +该程序当前阶段还缺少许多功能,**希望有人能加入一起完善**! +#### 软件/技术交流群:755655813 -目前仅测试过天天象棋和JJ象棋,JJ象棋因为等待时有动画,所以识别效果不是很理想。 +## 软件简介 -该程序当前阶段只是一个想法验证,还缺少许多功能,**希望有人能加入一起完善**! -#### 交流群:755655813 +#### 0、界面介绍 -## 使用方法 +![image-20220711145322503](assets/image-20220711145322503.png) + +**1、识别画面** + +![image-20220711145437807](assets/image-20220711145437807.png) + +显示Yolo模型对画面的识别情况 + +**2、识别结果** + +![image-20220711145528668](assets/image-20220711145528668.png) + +显示目前局面的稳定识别结果以及引擎的走法,**注意:该部分棋子可以点击,点击时会自动把对棋子的点击转发到被连线的游戏和软件中,方便对游戏中点击位置进行调试** + +**3、引擎设置** + +![image-20220711145715450](assets/image-20220711145715450.png) + +**4、识别设置** + +![image-20220711145734293](assets/image-20220711145734293.png) + +**5、引擎思考输出** + +![image-20220711145912807](assets/image-20220711145912807.png) + +**6、引擎设置** + +![image-20220711145946599](assets/image-20220711145946599.png) + +通过UCI或者UCCI协议获取到的关于引擎的设置选项 + +**7、开局库设置** + +![image-20220711150033775](assets/image-20220711150033775.png) + +选择是否使用云库和开局库 + +**8、自动点击管理** + +![image-20220711150109702](assets/image-20220711150109702.png) + +当连线设置中的自动点击被勾选时,软件会自动点击画面中保存模板的位置,可以实现自动续盘等功能。 + +使用方式:在右侧的画面中,点击需要框选的区域的左上和右下的点,确认无误后点击保存,即可保存自动点击的模板。 + +**9、保存方案** + +![image-20220711150256531](assets/image-20220711150256531.png) + +当使用 “寻找窗口句柄” 功能创建方案后,确定方案可用后,点击 “保存当前方案” 即可将当前方案保存下来下次使用。 + +**需要注意的是,如果截图标题中包含有关当前对局或者网址的信息,可以将截图标题删去,保留截图类,可能方案会更通用。** #### 1、创建方案或使用内置方案 @@ -44,26 +96,41 @@ #### 2、确认窗体缩放比 1. 选中你想要使用的方案 +2. ![image-20220711143552442](assets/image-20220711143552442.png) +3. 根据左上角截图情况调整缩放比:如果截图显示不全,则增大缩放比;如果截图存在黑边,就减小缩放比,直到窗口完美覆盖图片。 +4. 关闭调试状态 -2. 勾选调试模式 +#### 3、前台与后台 - ![image-20220705022934060](assets/image-20220705022934060.png) +![image-20220711143729937](assets/image-20220711143729937.png) -3. 根据左上角截图清空调整缩放比:如果截图显示不全,则增大缩放比;如果截图存在黑边,就减小缩放比,直到窗口完美覆盖图片。 +#### 截图模式 -4. 关闭调试状态 +**后台截图:仅对窗口,而不是整个桌面进行截屏,在该模式下,连线的目标窗体可以被遮挡,不影响截图。** -#### 3、开始下棋 +但需要注意的是,该模式并非通用方法,有的游戏和软件因为渲染方式的不同,并不能使用该方式截到图,这时调试状态显示的画面为黑色的。如果遇到这类软件,就需要勾选前台截图,使用截取屏幕的方式进行截图。 -​ 1.勾选自动走棋 +**前台截图:通用模式,所有游戏和软件都可以使用,但是要求窗口不能被遮挡。** -​ 2.对于等待中没有动画的棋盘(如天天象棋)则关闭持续识别模式;对于等待中存在动画的棋盘(如JJ象棋)则打开持续识别模式 +#### 鼠标模式 -​ 3.打开象棋对局 +**后台鼠标:通过给目标窗口发送系统消息的方式进行鼠标操作,不是所有软件和游戏都能用。** -​ 4.这时连线应该已经自动开始了,如没有开始,则点击重新检测棋盘来刷新 +该方式允许你在进行连线的时候鼠标同时操作别的事务,请优先选择该模式,如果遇到点击失败,则勾选前台鼠标模式。 -![image-20220705022917134](assets/image-20220705022917134.png) +**前台鼠标:通用模式,所有游戏和软件都可以用,但是会占用鼠标,如果在连线点击下棋的过程中移动了鼠标,就有可能导致点击失败。** + + + +#### 3、开始下棋 + +​ 1.打开游戏中的对局 + +​ 2.根据当前轮到我方或者对方,选择我方开始或是对方开始 + +​ 3.这时连线应该已经自动开始了,如没有开始,则点击重新检测棋盘来刷新 + +![image-20220711145322503](assets/image-20220711145322503.png) #### 4、自动续盘 @@ -95,7 +162,7 @@ ##### 4. 勾选自动点击 -![image-20220705023904934](assets/image-20220705023904934.png) +![image-20220711150802910](assets/image-20220711150802910.png) 启用自动点击后,即可自动点击保存截图中的按钮,进行自动续盘 @@ -106,3 +173,5 @@ 对于不能点击的情况,可以勾选前台鼠标,该方式占用鼠标进行点击,为通用方法。 如使用过程中出现停止分析(持续识别模式时有概率出现),则点击重新检测棋盘来检测。 + +**如果更多问题或者发现Bug,请加入软件/技术交流群:755655813,来反馈!** diff --git a/README.png b/README.png new file mode 100644 index 0000000..cdcd656 Binary files /dev/null and b/README.png differ diff --git a/VinXiangQi/DetectionLogic.cs b/VinXiangQi/DetectionLogic.cs index 0bda9a2..875967d 100644 --- a/VinXiangQi/DetectionLogic.cs +++ b/VinXiangQi/DetectionLogic.cs @@ -51,7 +51,7 @@ partial class Mainform public string ExpectedMove = ""; public bool ChangeDetectedAfterClick = false; - public bool StartFromOpponent = false; + public bool TurnToOpponent = false; public bool BackgroundAnalyzing = false; //Dictionary TemplateList = new Dictionary(); @@ -99,6 +99,7 @@ void AutoClickLoop() void DetectionLoop() { int gcCount = 0; + int getHandleCount = 0; while (Running) { DateTime startTime = DateTime.Now; @@ -118,6 +119,15 @@ void DetectionLoop() } if (GameHandle == IntPtr.Zero || !DetectEnabled) { + if (Settings.SelectedSolution != "") + { + getHandleCount++; + if (getHandleCount % 10 == 0) + { + getHandleCount = 0; + comboBox_solution_SelectedIndexChanged(this, null); + } + } Thread.Sleep(100); continue; } @@ -304,7 +314,7 @@ bool CheckNewBoard() if (Settings.AutoGo && !ChangeDetectedAfterClick) { AutoGoFailingCheckCount++; - if (AutoGoFailingCheckCount >= 3 && ClickRetryCount < 2) + if (AutoGoFailingCheckCount >= 5 && ClickRetryCount < 2) { AutoGoFailingCheckCount = 0; ClickRetryCount++; @@ -385,11 +395,7 @@ bool GetBoardFromPrediction(List predictions, bool refreshBoard { tmpBoard[xPos, yPos] = prediction.Label.Name; } - else if (xPos == -1 || xPos == 9 || yPos == -1 || yPos == 10) - { - Debug.WriteLine(prediction.Label.Name + " 位置检测错误"); - return false; - } + if (prediction.Label.Name == "r_jiang") { if (yPos < 5) @@ -566,33 +572,29 @@ await Task.Run(new Action(() => void ReloadBoard() { + if (CurrentBoard == null) return; var compareWithLast = Utils.CompareBoard(LastBoard, CurrentBoard); var compareWithExpected = Utils.CompareBoard(ExpectedSelfGoBoard, CurrentBoard); if (compareWithLast.DiffCount == 0) return; string opponentSymbol =RedSide ? "b_" : "r_"; string mySymbol = RedSide ? "r_" : "b_"; Debug.WriteLine($"Diff Result: {compareWithLast.DiffCount} R: {compareWithLast.RedDiff} B: {compareWithLast.BlackDiff}"); - if (StartFromOpponent) + string startingFen = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR"; + string currentFen = Utils.BoardToFen(CurrentBoard, RedSide ? "w" : "b", RedSide ? "w" : "b"); + if (currentFen.StartsWith(startingFen) && !RedSide) { - StartFromOpponent = false; - if (Settings.AnalyzingMode) - { - InvalidCount = 0; - LastBoard = (string[,])CurrentBoard.Clone(); - DisplayStatus("分析对手"); - string oppofen = Utils.BoardToFen(CurrentBoard,RedSide ? "w" : "b",RedSide ? "b" : "w"); - EngineAnalyzingBoard = (string[,])CurrentBoard.Clone(); - StartAnalyze(oppofen); - } - else - { - LastBoard = (string[,])CurrentBoard.Clone(); - ExpectedSelfGoBoard = null; - ExpectedMove = ""; - RenderDisplayBoard(); - DisplayStatus("从对手开始"); - return; - } + TurnToOpponent = true; + } + + if (TurnToOpponent && !Settings.AnalyzingMode) + { + TurnToOpponent = false; + LastBoard = (string[,])CurrentBoard.Clone(); + ExpectedSelfGoBoard = null; + ExpectedMove = ""; + RenderDisplayBoard(); + DisplayStatus("从对手开始,跳过当前局面"); + return; } if (compareWithLast.BlackDiff > 1 || compareWithLast.RedDiff > 1) { @@ -616,29 +618,37 @@ void ReloadBoard() } return; } - if (compareWithLast.DiffCount == 2 && compareWithLast.Chess != null && compareWithLast.Chess.Contains(mySymbol)) + if (compareWithLast.DiffCount == 2 && compareWithLast.Chess != null) { - RenderDisplayBoard(); - if (Settings.AnalyzingMode) + if (compareWithLast.Chess.Contains(mySymbol)) { - InvalidCount = 0; - LastBoard = (string[,])CurrentBoard.Clone(); - EngineAnalyzeCount++; - DisplayStatus("开始引擎计算"); - string oppofen = Utils.BoardToFen(CurrentBoard,RedSide ? "w" : "b",RedSide ? "b" : "w"); - EngineAnalyzingBoard = (string[,])CurrentBoard.Clone(); - Engine.StartAnalyze(oppofen, Settings.EngineStepTime, Settings.EngineDepth); + RenderDisplayBoard(); + if (Settings.AnalyzingMode) + { + InvalidCount = 0; + LastBoard = (string[,])CurrentBoard.Clone(); + EngineAnalyzeCount++; + DisplayStatus("开始引擎计算"); + string oppofen = Utils.BoardToFen(CurrentBoard, RedSide ? "w" : "b", RedSide ? "b" : "w"); + EngineAnalyzingBoard = (string[,])CurrentBoard.Clone(); + Engine.StopAnalyze(); + StartAnalyze(oppofen); + } + else + { + InvalidCount = 0; + LastBoard = (string[,])CurrentBoard.Clone(); + DisplayStatus("己方棋子变化,跳过分析"); + ExpectedMove = ""; + } + return; } else { - InvalidCount = 0; - LastBoard = (string[,])CurrentBoard.Clone(); - DisplayStatus("己方棋子变化,跳过分析"); - ExpectedMove = ""; + TurnToOpponent = false; } - return; } - if (compareWithExpected.DiffCount == 0) + if (compareWithExpected.DiffCount == 0 && !Settings.AnalyzingMode) { LastBoard = (string[,])CurrentBoard.Clone(); ExpectedMove = ""; @@ -662,6 +672,24 @@ void ReloadBoard() EngineAnalyzeCount++; LastBoard = (string[,])CurrentBoard.Clone(); + if (Settings.AnalyzingMode) + { + InvalidCount = 0; + string analyzeFen; + if (TurnToOpponent) + { + analyzeFen = Utils.BoardToFen(CurrentBoard, RedSide ? "w" : "b", RedSide ? "b" : "w"); + } + else + { + analyzeFen = Utils.BoardToFen(CurrentBoard, RedSide ? "w" : "b", RedSide ? "w" : "b"); + } + Engine.StopAnalyze(); + EngineAnalyzingBoard = (string[,])CurrentBoard.Clone(); + StartAnalyze(analyzeFen); + return; + } + string fen = Utils.BoardToFen(CurrentBoard,RedSide ? "w" : "b",RedSide ? "w" : "b"); if (Settings.BackgroundAnalysis && BackgroundAnalyzing) { diff --git a/VinXiangQi/EngineHelper.cs b/VinXiangQi/EngineHelper.cs index 8c43da3..f5fb8d2 100644 --- a/VinXiangQi/EngineHelper.cs +++ b/VinXiangQi/EngineHelper.cs @@ -25,6 +25,7 @@ public class EngineHelper public int AnalyzeCount = 0; public int SkipCount = 0; public DateTime LastOutputTime = new DateTime(); + public string IgnoreMove = ""; public EngineHelper(string enginePath, Dictionary configs = null) @@ -40,7 +41,7 @@ public void Stop() { try { - if (Engine != null && Engine.Handle != IntPtr.Zero && !Engine.HasExited) + if (Engine != null) { Engine.Kill(); } @@ -66,7 +67,22 @@ public void Init() Engine.StartInfo.WorkingDirectory = string.Join("\\", pathParams.Take(pathParams.Length - 1)); Engine.OutputDataReceived += Engine_OutputDataReceived; Engine.Start(); - Engine.PriorityClass = ProcessPriorityClass.BelowNormal; + int tryCount = 10; + bool success = false; + while (!success && tryCount > 0) + { + tryCount--; + try + { + Engine.PriorityClass = ProcessPriorityClass.BelowNormal; + success = true; + } + catch (Exception ex) + { + Debug.WriteLine("加载引擎时失败: " + ex.ToString()); + Thread.Sleep(500); + } + } ThreadHandleOutput = new Thread(new ThreadStart(WaitForExit)); ThreadHandleOutput.Start(); Engine.BeginOutputReadLine(); diff --git a/VinXiangQi/Mainform.Designer.cs b/VinXiangQi/Mainform.Designer.cs index 74677c5..73e28b1 100644 --- a/VinXiangQi/Mainform.Designer.cs +++ b/VinXiangQi/Mainform.Designer.cs @@ -908,7 +908,7 @@ private void InitializeComponent() this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MainMenuStrip = this.menuStrip1; this.Name = "Mainform"; - this.Text = "VIN 象棋 1.3.0"; + this.Text = "VIN 象棋 1.3.2"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Mainform_FormClosing); this.Load += new System.EventHandler(this.Mainform_Load); this.tableLayoutPanel_main.ResumeLayout(false); diff --git a/VinXiangQi/Mainform.cs b/VinXiangQi/Mainform.cs index 257f928..b0d085f 100644 --- a/VinXiangQi/Mainform.cs +++ b/VinXiangQi/Mainform.cs @@ -416,7 +416,7 @@ void StartDetection(bool fromOpponent) Engine.PonderMiss(); BackgroundAnalyzing = false; } - StartFromOpponent = fromOpponent; + TurnToOpponent = fromOpponent; DetectEnabled = true; ResetDetection(); ModeDisplay(); @@ -893,6 +893,12 @@ private void checkBox_debug_CheckedChanged(object sender, EventArgs e) private void checkBox_analyze_mode_CheckedChanged(object sender, EventArgs e) { + if (Engine != null) + { + Engine.StopAnalyze(); + Engine.AnalyzeCount = 0; + Engine.SkipCount = 0; + } Settings.AnalyzingMode = checkBox_analyze_mode.Checked; if (Settings.AnalyzingMode) { @@ -1020,7 +1026,10 @@ private void button_stop_detection_Click(object sender, EventArgs e) { DetectEnabled = false; checkBox_debug.Checked = true; - Engine.Stop(); + if (Engine != null) + { + Engine.Stop(); + } ModeDisplay(); } diff --git a/VinXiangQi/Resources/icon_dev.png b/VinXiangQi/Resources/icon_dev.png new file mode 100644 index 0000000..5731824 Binary files /dev/null and b/VinXiangQi/Resources/icon_dev.png differ diff --git a/VinXiangQi/Resources/icon_dev.psd b/VinXiangQi/Resources/icon_dev.psd new file mode 100644 index 0000000..837931f Binary files /dev/null and b/VinXiangQi/Resources/icon_dev.psd differ diff --git a/VinXiangQi/test.py b/VinXiangQi/test.py deleted file mode 100644 index d22def2..0000000 --- a/VinXiangQi/test.py +++ /dev/null @@ -1,81 +0,0 @@ -import win32gui -import win32ui -import win32api -import time -from ctypes import windll -from PIL import Image -from win32con import WM_LBUTTONDOWN, MK_LBUTTON, WM_LBUTTONUP, WM_MOUSEMOVE -import matplotlib.pyplot as plt - - -def LeftClick(handle, pos): - x, y = pos - # print(pos, "Realsize", self.RealSize) - lParam = win32api.MAKELONG(x, y) - win32gui.PostMessage(handle, WM_MOUSEMOVE, MK_LBUTTON, lParam) - win32gui.PostMessage(handle, WM_LBUTTONDOWN, MK_LBUTTON, lParam) - time.sleep(0.5) - win32gui.PostMessage(handle, WM_LBUTTONUP, MK_LBUTTON, lParam) - win32gui.PostMessage(handle, WM_MOUSEMOVE, MK_LBUTTON, lParam) - time.sleep(0.5) - -def Screenshot(hwnd, region=None): # -> (im, (left, top)) - try_count = 3 - success = False - while try_count > 0 and not success: - try: - try_count -= 1 - left, top, right, bot = win32gui.GetWindowRect(hwnd) - width = right - left - height = bot - top - # self.RealSize = (width, height) - hwndDC = win32gui.GetWindowDC(hwnd) - mfcDC = win32ui.CreateDCFromHandle(hwndDC) - saveDC = mfcDC.CreateCompatibleDC() - saveBitMap = win32ui.CreateBitmap() - saveBitMap.CreateCompatibleBitmap(mfcDC, width, height) - saveDC.SelectObject(saveBitMap) - result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 0) - bmpinfo = saveBitMap.GetInfo() - bmpstr = saveBitMap.GetBitmapBits(True) - im = Image.frombuffer( - "RGB", - (bmpinfo['bmWidth'], bmpinfo['bmHeight']), - bmpstr, 'raw', 'BGRX', 0, 1) - win32gui.DeleteObject(saveBitMap.GetHandle()) - saveDC.DeleteDC() - mfcDC.DeleteDC() - win32gui.ReleaseDC(hwnd, hwndDC) - if region is not None: - im = im.crop((region[0], region[1], region[0] + region[2], region[1] + region[3])) - if result: - success = True - return im, (left, top, width, height) - except Exception as e: - print("截图时出现错误:", repr(e)) - return None, (0, 0) - -def ShowImg(image): - plt.imshow(image) - plt.show() - -hwnd1 = win32gui.FindWindow(None, "QQ新中国象棋") -print("hwnd1", hwnd1) -hwnd2 = win32gui.FindWindowEx(hwnd1, 0, "CGameView", None) -print("hwnd2", hwnd2) -# hwnd2 = win32gui.FindWindowEx(hwnd2, 0, None, 'sub') -# print("hwnd2", hwnd2) -# hwnd3 = win32gui.FindWindow(None, "sub") -# print("hwnd3", hwnd3) -time.sleep(2) -h4 = win32gui.GetForegroundWindow(); -# get cursor position -x, y = win32api.GetCursorPos() -h5 = win32gui.WindowFromPoint((x, y)); -print("h4", h4) -print("h5", h5) -# img, _ = Screenshot(0x00720ddc) -handle = hwnd1 -# LeftClick(handle, (300, 300)) -# LeftClick(handle, (, 1348)) -# ShowImg(img) \ No newline at end of file diff --git a/assets/image-20220711142428696.png b/assets/image-20220711142428696.png new file mode 100644 index 0000000..9ae0280 Binary files /dev/null and b/assets/image-20220711142428696.png differ diff --git a/assets/image-20220711143552442.png b/assets/image-20220711143552442.png new file mode 100644 index 0000000..3e7a86a Binary files /dev/null and b/assets/image-20220711143552442.png differ diff --git a/assets/image-20220711143706133.png b/assets/image-20220711143706133.png new file mode 100644 index 0000000..bdde21c Binary files /dev/null and b/assets/image-20220711143706133.png differ diff --git a/assets/image-20220711143708250.png b/assets/image-20220711143708250.png new file mode 100644 index 0000000..bdde21c Binary files /dev/null and b/assets/image-20220711143708250.png differ diff --git a/assets/image-20220711143729937.png b/assets/image-20220711143729937.png new file mode 100644 index 0000000..6e52c21 Binary files /dev/null and b/assets/image-20220711143729937.png differ diff --git a/assets/image-20220711145322503.png b/assets/image-20220711145322503.png new file mode 100644 index 0000000..62a396d Binary files /dev/null and b/assets/image-20220711145322503.png differ diff --git a/assets/image-20220711145348990.png b/assets/image-20220711145348990.png new file mode 100644 index 0000000..aa67e5e Binary files /dev/null and b/assets/image-20220711145348990.png differ diff --git a/assets/image-20220711145437807.png b/assets/image-20220711145437807.png new file mode 100644 index 0000000..5490563 Binary files /dev/null and b/assets/image-20220711145437807.png differ diff --git a/assets/image-20220711145528668.png b/assets/image-20220711145528668.png new file mode 100644 index 0000000..b9c2997 Binary files /dev/null and b/assets/image-20220711145528668.png differ diff --git a/assets/image-20220711145715450.png b/assets/image-20220711145715450.png new file mode 100644 index 0000000..6082bd6 Binary files /dev/null and b/assets/image-20220711145715450.png differ diff --git a/assets/image-20220711145734293.png b/assets/image-20220711145734293.png new file mode 100644 index 0000000..79f150c Binary files /dev/null and b/assets/image-20220711145734293.png differ diff --git a/assets/image-20220711145912807.png b/assets/image-20220711145912807.png new file mode 100644 index 0000000..c4d6bfb Binary files /dev/null and b/assets/image-20220711145912807.png differ diff --git a/assets/image-20220711145946599.png b/assets/image-20220711145946599.png new file mode 100644 index 0000000..078ed15 Binary files /dev/null and b/assets/image-20220711145946599.png differ diff --git a/assets/image-20220711150033775.png b/assets/image-20220711150033775.png new file mode 100644 index 0000000..82d86e2 Binary files /dev/null and b/assets/image-20220711150033775.png differ diff --git a/assets/image-20220711150109702.png b/assets/image-20220711150109702.png new file mode 100644 index 0000000..dc09819 Binary files /dev/null and b/assets/image-20220711150109702.png differ diff --git a/assets/image-20220711150256531.png b/assets/image-20220711150256531.png new file mode 100644 index 0000000..8e04f3f Binary files /dev/null and b/assets/image-20220711150256531.png differ diff --git a/assets/image-20220711150802910.png b/assets/image-20220711150802910.png new file mode 100644 index 0000000..ffd08dc Binary files /dev/null and b/assets/image-20220711150802910.png differ diff --git "a/\344\275\277\347\224\250\350\257\264\346\230\216.pdf" "b/\344\275\277\347\224\250\350\257\264\346\230\216.pdf" new file mode 100644 index 0000000..9a9a9a9 Binary files /dev/null and "b/\344\275\277\347\224\250\350\257\264\346\230\216.pdf" differ