├── .gitattributes
├── .gitignore
├── About.Designer.cs
├── About.cs
├── About.en.resx
├── About.resx
├── About.zh-CN.resx
├── App.config
├── AutoTask
├── BaseJob.cs
├── SelectDevice.Designer.cs
├── SelectDevice.cs
├── SelectDevice.resx
├── TaskEdit.Designer.cs
├── TaskEdit.cs
├── TaskEdit.resx
├── TaskEditItem.Designer.cs
├── TaskEditItem.cs
├── TaskEditItem.resx
├── TaskJson.cs
├── TaskList.Designer.cs
├── TaskList.cs
├── TaskList.resx
├── TaskRun.cs
├── TaskRunWindow.Designer.cs
├── TaskRunWindow.cs
├── TaskRunWindow.resx
├── TaskShowItem.Designer.cs
├── TaskShowItem.cs
└── TaskShowItem.resx
├── Base
├── ADB.cs
├── ADBKey.cs
├── AdbParse.cs
├── CMD.cs
├── FireWallHelper.cs
├── GlobalHotkey.cs
├── ProcessWindowController.cs
├── Scrcpy.cs
├── ScrcpyParam.cs
└── ScrcpyParamAttribute.cs
├── BaseControl.Designer.cs
├── BaseControl.cs
├── BaseControl.resx
├── BaseForm.cs
├── BaseForm.resx
├── Docs
├── Task.md
├── Update.en.md
├── Update.md
├── autohotkey.ahk
└── task.json
├── HotKeyControl.Designer.cs
├── HotKeyControl.cs
├── HotKeyControl.resx
├── HotKeySetting.Designer.cs
├── HotKeySetting.cs
├── HotKeySetting.en.resx
├── HotKeySetting.resx
├── HotKeySetting.zh-CN.resx
├── IPConnect.Designer.cs
├── IPConnect.cs
├── IPConnect.en.resx
├── IPConnect.resx
├── IPConnect.zh-CN.resx
├── IPPair.Designer.cs
├── IPPair.cs
├── IPPair.en.resx
├── IPPair.resx
├── LICENSE
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.en.resx
├── MainForm.resx
├── MainForm.zh-CN.resx
├── MainForm.zh-Hans.resx
├── MobileControlGuru.csproj
├── MobileControlGuru.sln
├── MoblieControl.Designer.cs
├── MoblieControl.cs
├── MoblieControl.en.resx
├── MoblieControl.resx
├── MoblieControl.zh-Hans.resx
├── Model
├── Device.cs
└── KeyItem.cs
├── Preview
├── api.png
├── hotkeysetting.en.png
├── hotkeysetting.png
├── ipconnect.en.png
├── ipconnect.png
├── main.en.png
├── main.png
├── taskedit.png
└── taskmain.png
├── Program.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── README.en.md
├── README.md
├── Resources
├── fanhui.png
├── favicon.ico
├── jietu.png
├── nosee.png
├── ontop.png
├── ontop_blur.png
├── scrcpy-win64-v2.4.zip
├── scrcpy_params.json
├── see.bmp
├── see.png
├── shouye.png
├── to_top.png
└── to_top_blur.png
├── ScrcpyConrtrolPanel.Designer.cs
├── ScrcpyConrtrolPanel.cs
├── ScrcpyConrtrolPanel.resx
├── ScrcpyForm.Designer.cs
├── ScrcpyForm.cs
├── ScrcpyForm.resx
├── ScrcpySetting.Designer.cs
├── ScrcpySetting.cs
├── ScrcpySetting.en.resx
├── ScrcpySetting.resx
├── ScrcpySetting.zh-CN.resx
├── Src
├── DeviceADB.cs
├── DeviceManager.cs
├── MyHotKey.cs
├── ScrcpyMonitor.cs
└── TaskManager.cs
├── Tools
├── Common.cs
├── ConfigHelp.cs
├── JsonHelp.cs
├── LanguageHelper.cs
├── LogHelper.cs
├── QuartzJobUtil.cs
└── ZipHelper.cs
├── WebAPI
├── Controllers
│ ├── DeviceController.cs
│ └── HomeController.cs
├── Startup.cs
└── WebHelper.cs
├── adb_cmds.txt
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 | *.vcxproj.filters
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # .NET Core
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 | **/Properties/launchSettings.json
51 |
52 | *_i.c
53 | *_p.c
54 | *_i.h
55 | *.ilk
56 | *.meta
57 | *.obj
58 | *.pch
59 | *.pdb
60 | *.pgc
61 | *.pgd
62 | *.rsp
63 | *.sbr
64 | *.tlb
65 | *.tli
66 | *.tlh
67 | *.tmp
68 | *.tmp_proj
69 | *.log
70 | *.vspscc
71 | *.vssscc
72 | .builds
73 | *.pidb
74 | *.svclog
75 | *.scc
76 |
77 | # Chutzpah Test files
78 | _Chutzpah*
79 |
80 | # Visual C++ cache files
81 | ipch/
82 | *.aps
83 | *.ncb
84 | *.opendb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 | *.VC.db
89 | *.VC.VC.opendb
90 |
91 | # Visual Studio profiler
92 | *.psess
93 | *.vsp
94 | *.vspx
95 | *.sap
96 |
97 | # TFS 2012 Local Workspace
98 | $tf/
99 |
100 | # Guidance Automation Toolkit
101 | *.gpState
102 |
103 | # ReSharper is a .NET coding add-in
104 | _ReSharper*/
105 | *.[Rr]e[Ss]harper
106 | *.DotSettings.user
107 |
108 | # JustCode is a .NET coding add-in
109 | .JustCode
110 |
111 | # TeamCity is a build add-in
112 | _TeamCity*
113 |
114 | # DotCover is a Code Coverage Tool
115 | *.dotCover
116 |
117 | # Visual Studio code coverage results
118 | *.coverage
119 | *.coveragexml
120 |
121 | # NCrunch
122 | _NCrunch_*
123 | .*crunch*.local.xml
124 | nCrunchTemp_*
125 |
126 | # MightyMoose
127 | *.mm.*
128 | AutoTest.Net/
129 |
130 | # Web workbench (sass)
131 | .sass-cache/
132 |
133 | # Installshield output folder
134 | [Ee]xpress/
135 |
136 | # DocProject is a documentation generator add-in
137 | DocProject/buildhelp/
138 | DocProject/Help/*.HxT
139 | DocProject/Help/*.HxC
140 | DocProject/Help/*.hhc
141 | DocProject/Help/*.hhk
142 | DocProject/Help/*.hhp
143 | DocProject/Help/Html2
144 | DocProject/Help/html
145 |
146 | # Click-Once directory
147 | publish/
148 |
149 | # Publish Web Output
150 | *.[Pp]ublish.xml
151 | *.azurePubxml
152 | # TODO: Comment the next line if you want to checkin your web deploy settings
153 | # but database connection strings (with potential passwords) will be unencrypted
154 | *.pubxml
155 | *.publishproj
156 |
157 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
158 | # checkin your Azure Web App publish settings, but sensitive information contained
159 | # in these scripts will be unencrypted
160 | PublishScripts/
161 |
162 | # NuGet Packages
163 | *.nupkg
164 | # The packages folder can be ignored because of Package Restore
165 | **/packages/*
166 | # except build/, which is used as an MSBuild target.
167 | !**/packages/build/
168 | # Uncomment if necessary however generally it will be regenerated when needed
169 | #!**/packages/repositories.config
170 | # NuGet v3's project.json files produces more ignoreable files
171 | *.nuget.props
172 | *.nuget.targets
173 |
174 | # Microsoft Azure Build Output
175 | csx/
176 | *.build.csdef
177 |
178 | # Microsoft Azure Emulator
179 | ecf/
180 | rcf/
181 |
182 | # Windows Store app package directories and files
183 | AppPackages/
184 | BundleArtifacts/
185 | Package.StoreAssociation.xml
186 | _pkginfo.txt
187 |
188 | # Visual Studio cache files
189 | # files ending in .cache can be ignored
190 | *.[Cc]ache
191 | # but keep track of directories ending in .cache
192 | !*.[Cc]ache/
193 |
194 | # Others
195 | ClientBin/
196 | ~$*
197 | *~
198 | *.dbmdl
199 | *.dbproj.schemaview
200 | *.jfm
201 | *.pfx
202 | *.publishsettings
203 | node_modules/
204 | orleans.codegen.cs
205 |
206 | # Since there are multiple workflows, uncomment next line to ignore bower_components
207 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
208 | #bower_components/
209 |
210 | # RIA/Silverlight projects
211 | Generated_Code/
212 |
213 | # Backup & report files from converting an old project file
214 | # to a newer Visual Studio version. Backup files are not needed,
215 | # because we have git ;-)
216 | _UpgradeReport_Files/
217 | Backup*/
218 | UpgradeLog*.XML
219 | UpgradeLog*.htm
220 |
221 | # SQL Server files
222 | *.mdf
223 | *.ldf
224 |
225 | # Business Intelligence projects
226 | *.rdl.data
227 | *.bim.layout
228 | *.bim_*.settings
229 |
230 | # Microsoft Fakes
231 | FakesAssemblies/
232 |
233 | # GhostDoc plugin setting file
234 | *.GhostDoc.xml
235 |
236 | # Node.js Tools for Visual Studio
237 | .ntvs_analysis.dat
238 |
239 | # Visual Studio 6 build log
240 | *.plg
241 |
242 | # Visual Studio 6 workspace options file
243 | *.opt
244 |
245 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
246 | *.vbw
247 |
248 | # Visual Studio LightSwitch build output
249 | **/*.HTMLClient/GeneratedArtifacts
250 | **/*.DesktopClient/GeneratedArtifacts
251 | **/*.DesktopClient/ModelManifest.xml
252 | **/*.Server/GeneratedArtifacts
253 | **/*.Server/ModelManifest.xml
254 | _Pvt_Extensions
255 |
256 | # Paket dependency manager
257 | .paket/paket.exe
258 | paket-files/
259 |
260 | # FAKE - F# Make
261 | .fake/
262 |
263 | # JetBrains Rider
264 | .idea/
265 | *.sln.iml
266 |
267 | # CodeRush
268 | .cr/
269 |
270 | # Python Tools for Visual Studio (PTVS)
271 | __pycache__/
272 | *.pyc
273 |
274 | # Cake - Uncomment if you are using it
275 | # tools/
276 |
--------------------------------------------------------------------------------
/About.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class About
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(About));
32 | this.linkLabel1 = new System.Windows.Forms.LinkLabel();
33 | this.label1 = new AntdUI.Label();
34 | this.linkLabel2 = new System.Windows.Forms.LinkLabel();
35 | this.linkLabel3 = new System.Windows.Forms.LinkLabel();
36 | this.SuspendLayout();
37 | //
38 | // linkLabel1
39 | //
40 | resources.ApplyResources(this.linkLabel1, "linkLabel1");
41 | this.linkLabel1.Name = "linkLabel1";
42 | this.linkLabel1.TabStop = true;
43 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
44 | //
45 | // label1
46 | //
47 | resources.ApplyResources(this.label1, "label1");
48 | this.label1.Name = "label1";
49 | //
50 | // linkLabel2
51 | //
52 | resources.ApplyResources(this.linkLabel2, "linkLabel2");
53 | this.linkLabel2.Name = "linkLabel2";
54 | this.linkLabel2.TabStop = true;
55 | this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked);
56 | //
57 | // linkLabel3
58 | //
59 | resources.ApplyResources(this.linkLabel3, "linkLabel3");
60 | this.linkLabel3.Name = "linkLabel3";
61 | this.linkLabel3.TabStop = true;
62 | this.linkLabel3.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel3_LinkClicked);
63 | //
64 | // About
65 | //
66 | resources.ApplyResources(this, "$this");
67 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
68 | this.Controls.Add(this.linkLabel3);
69 | this.Controls.Add(this.linkLabel2);
70 | this.Controls.Add(this.label1);
71 | this.Controls.Add(this.linkLabel1);
72 | this.Name = "About";
73 | this.ResumeLayout(false);
74 | this.PerformLayout();
75 |
76 | }
77 |
78 | #endregion
79 |
80 | private System.Windows.Forms.LinkLabel linkLabel1;
81 | private AntdUI.Label label1;
82 | private System.Windows.Forms.LinkLabel linkLabel2;
83 | private System.Windows.Forms.LinkLabel linkLabel3;
84 | }
85 | }
--------------------------------------------------------------------------------
/About.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace MobileControlGuru
12 | {
13 | public partial class About : Form
14 | {
15 | public About()
16 | {
17 | InitializeComponent();
18 | }
19 |
20 | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
21 | {
22 | System.Diagnostics.Process.Start("https://github.com/yclown/MobileControlGuru");
23 | }
24 |
25 | private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
26 | {
27 | System.Diagnostics.Process.Start("https://wwo.lanzouo.com/b0064zc4ve?pwd=7njs");
28 | }
29 |
30 | private void linkLabel3_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
31 | {
32 | System.Diagnostics.Process.Start("https://github.com/yclown/MobileControlGuru/releases");
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | 0, 0
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/AutoTask/BaseJob.cs:
--------------------------------------------------------------------------------
1 | using Quartz;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MobileControlGuru.AutoTask
9 | {
10 | public class BaseJob : IJob
11 | {
12 | public Task Execute(IJobExecutionContext context)
13 | {
14 | JobKey key = context.JobDetail.Key;
15 | JobDataMap dataMap = context.JobDetail.JobDataMap;
16 | //string devicename = dataMap.GetString("devicename");
17 | TaskJson.TaskInfo taskInfo = (TaskJson.TaskInfo)dataMap.Get("taskInfo");
18 |
19 | return Task.Factory.StartNew(() =>
20 | {
21 | TaskRun taskRun = new TaskRun(taskInfo.DeviceName, taskInfo);
22 | taskRun.Run();
23 | });
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/AutoTask/SelectDevice.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru.AutoTask
2 | {
3 | partial class SelectDevice
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.select1 = new AntdUI.Select();
32 | this.button1 = new AntdUI.Button();
33 | this.SuspendLayout();
34 | //
35 | // select1
36 | //
37 | this.select1.Location = new System.Drawing.Point(12, 12);
38 | this.select1.Name = "select1";
39 | this.select1.Size = new System.Drawing.Size(180, 39);
40 | this.select1.TabIndex = 0;
41 | this.select1.Text = "select1";
42 | //
43 | // button1
44 | //
45 | this.button1.Location = new System.Drawing.Point(98, 66);
46 | this.button1.Name = "button1";
47 | this.button1.Size = new System.Drawing.Size(94, 35);
48 | this.button1.TabIndex = 1;
49 | this.button1.Text = "确定";
50 | this.button1.Click += new System.EventHandler(this.button1_Click);
51 | //
52 | // SelectDevice
53 | //
54 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
55 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
56 | this.ClientSize = new System.Drawing.Size(201, 108);
57 | this.Controls.Add(this.button1);
58 | this.Controls.Add(this.select1);
59 | this.Name = "SelectDevice";
60 | this.Text = "SelectDevice";
61 | this.Load += new System.EventHandler(this.SelectDevice_Load);
62 | this.ResumeLayout(false);
63 |
64 | }
65 |
66 | #endregion
67 |
68 | public AntdUI.Select select1;
69 | public AntdUI.Button button1;
70 | }
71 | }
--------------------------------------------------------------------------------
/AutoTask/SelectDevice.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Src;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace MobileControlGuru.AutoTask
13 | {
14 | public partial class SelectDevice : Form
15 | {
16 | public SelectDevice()
17 | {
18 | InitializeComponent();
19 | }
20 |
21 | private void SelectDevice_Load(object sender, EventArgs e)
22 | {
23 | this.select1.Items =new AntdUI.BaseCollection();
24 | foreach(var d in DeviceManager.Instance.devices)
25 | {
26 | this.select1.Items.Add(d.Name);
27 | }
28 | this.select1.SelectedIndex = 0;
29 |
30 |
31 | }
32 |
33 | private void button1_Click(object sender, EventArgs e)
34 | {
35 |
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/AutoTask/SelectDevice.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/AutoTask/TaskEdit.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualBasic;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Data;
7 | using System.Drawing;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 |
13 | namespace MobileControlGuru.AutoTask
14 | {
15 | public partial class TaskEdit : BaseForm
16 | {
17 |
18 | public TaskJson.TaskInfo taskInfo;
19 |
20 | public TaskEdit()
21 | {
22 | InitializeComponent();
23 | }
24 |
25 | public TaskEdit(TaskJson.TaskInfo taskInfo)
26 | {
27 | this.taskInfo = taskInfo;
28 | InitializeComponent();
29 | }
30 | private void TaskEdit_Load(object sender, EventArgs e)
31 | {
32 | Init();
33 | }
34 |
35 | private void Init()
36 | {
37 |
38 | if (taskInfo != null)
39 | {
40 | this.task_name.Text = taskInfo.Name;
41 | this.devicename_input.Text = taskInfo.DeviceName;
42 | this.cornexp_input.Text = taskInfo.Corn;
43 |
44 | foreach (var item in taskInfo.TaskItems)
45 | {
46 | var edit = new TaskEditItem(item);
47 | edit.deleteEevnt += ItemDelete;
48 | this.flowLayoutPanel1.Controls.Add(edit);
49 | }
50 |
51 | }
52 |
53 |
54 | }
55 |
56 | private void button1_Click(object sender, EventArgs e)
57 | {
58 | var edit = new TaskEditItem();
59 | edit.deleteEevnt += ItemDelete;
60 |
61 | this.flowLayoutPanel1.Controls.Add(edit);
62 | UpdateItemIndex();
63 | }
64 | private void UpdateItemIndex()
65 | {
66 | int i = 0;
67 | foreach (TaskEditItem c in this.flowLayoutPanel1.Controls)
68 | {
69 | c.SetIndex(++i);
70 | }
71 | }
72 | private void button3_Click(object sender, EventArgs e)
73 | {
74 | this.flowLayoutPanel1.Controls.Clear();
75 | }
76 |
77 | private void button2_Click(object sender, EventArgs e)
78 | {
79 |
80 | var t= GetTaksInfo();
81 | if(t.id == 0)
82 | {
83 | TaskJson.AddTask(t);
84 | }
85 | else
86 | {
87 | TaskJson.EditTask(t);
88 | }
89 | this.Close();
90 |
91 | }
92 |
93 |
94 | public TaskJson.TaskInfo GetTaksInfo()
95 | {
96 | List list = new List();
97 |
98 | foreach (TaskEditItem c in this.flowLayoutPanel1.Controls)
99 | {
100 | list.Add(c.GetTaskInfo());
101 | }
102 |
103 | if(taskInfo != null)
104 | {
105 | taskInfo.TaskItems=list;
106 | taskInfo.Name=this.task_name.Text;
107 | taskInfo.DeviceName = this.devicename_input.Text;
108 | taskInfo.Corn = this.cornexp_input.Text;
109 | return taskInfo;
110 | }
111 | else
112 | {
113 | return new TaskJson.TaskInfo() {
114 | Name = task_name.Text,
115 | TaskItems = list,
116 | DeviceName=devicename_input.Text,
117 | Corn = cornexp_input.Text
118 | };
119 | }
120 |
121 | }
122 |
123 |
124 | public void ItemDelete(int index)
125 | {
126 | UpdateItemIndex();
127 | }
128 |
129 |
130 | SelectDevice selectDevice;
131 | private void button4_Click(object sender, EventArgs e)
132 | {
133 | var taskinfo = GetTaksInfo();
134 | TaskRunWindow tr = new TaskRunWindow(taskinfo, true);
135 | tr.Text = "debug on:" + taskinfo.DeviceName;
136 | tr.ShowDialog(this);
137 |
138 |
139 | //selectDevice = new SelectDevice();
140 | //selectDevice.button1.Click += SureDevice;
141 | //selectDevice.ShowDialog(this);
142 | //tr.Run();
143 |
144 |
145 | }
146 | private void SureDevice(object sender, EventArgs e)
147 | {
148 | var name= this.selectDevice.select1.SelectedValue.ToString();
149 | selectDevice.Dispose();
150 | TaskRunWindow tr = new TaskRunWindow(GetTaksInfo(),true);
151 | tr.Text = "debug on:"+name;
152 | tr.ShowDialog(this);
153 | }
154 |
155 | private void select1_SelectedIndexChanged(object sender, int value)
156 | {
157 |
158 | }
159 |
160 | private void button5_Click(object sender, EventArgs e)
161 | {
162 | //var time= QuartzJobUtil.GetNextTime(this.cornexp_input.Text, DateTime.Now);
163 |
164 | List five_runtime = new List();
165 | DateTime? lastTime = DateTime.Now;
166 | for (int i = 0; i < 5; i++)
167 | {
168 | var time = QuartzJobUtil.GetNextTime(this.cornexp_input.Text, lastTime);
169 |
170 | if (time != null)
171 | {
172 | five_runtime.Add(((DateTime)time).ToString("yyyy-MM-dd HH:mm:ss"));
173 | }
174 | lastTime = time;
175 | }
176 | MessageBox.Show(string.Join("\n", five_runtime),"最近5次运行时间");
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/AutoTask/TaskEditItem.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru.AutoTask
2 | {
3 | partial class TaskEditItem
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region 组件设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.label1 = new AntdUI.Label();
32 | this.button1 = new AntdUI.Button();
33 | this.input1 = new AntdUI.Input();
34 | this.select1 = new AntdUI.Select();
35 | this.SuspendLayout();
36 | //
37 | // label1
38 | //
39 | this.label1.Location = new System.Drawing.Point(4, 4);
40 | this.label1.Name = "label1";
41 | this.label1.Size = new System.Drawing.Size(73, 37);
42 | this.label1.TabIndex = 1;
43 | this.label1.Text = "操作";
44 | //
45 | // button1
46 | //
47 | this.button1.Location = new System.Drawing.Point(431, 4);
48 | this.button1.Name = "button1";
49 | this.button1.Size = new System.Drawing.Size(68, 37);
50 | this.button1.TabIndex = 2;
51 | this.button1.Text = "删 除";
52 | this.button1.Click += new System.EventHandler(this.button1_Click);
53 | //
54 | // input1
55 | //
56 | this.input1.Location = new System.Drawing.Point(194, 4);
57 | this.input1.Name = "input1";
58 | this.input1.Size = new System.Drawing.Size(231, 37);
59 | this.input1.TabIndex = 3;
60 | //
61 | // select1
62 | //
63 | this.select1.Location = new System.Drawing.Point(74, 3);
64 | this.select1.Name = "select1";
65 | this.select1.Size = new System.Drawing.Size(114, 37);
66 | this.select1.TabIndex = 4;
67 | this.select1.Text = "select1";
68 | this.select1.SelectedIndexChanged += new AntdUI.IntEventHandler(this.select1_SelectedIndexChanged);
69 | //
70 | // TaskEditItem
71 | //
72 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
73 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
74 | this.Controls.Add(this.select1);
75 | this.Controls.Add(this.input1);
76 | this.Controls.Add(this.button1);
77 | this.Controls.Add(this.label1);
78 | this.Name = "TaskEditItem";
79 | this.Size = new System.Drawing.Size(502, 48);
80 | this.Load += new System.EventHandler(this.TaskEditItem_Load);
81 | this.ResumeLayout(false);
82 |
83 | }
84 |
85 | #endregion
86 | private AntdUI.Label label1;
87 | private AntdUI.Button button1;
88 | private AntdUI.Input input1;
89 | private AntdUI.Select select1;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/AutoTask/TaskEditItem.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace MobileControlGuru.AutoTask
13 | {
14 | public partial class TaskEditItem : UserControl
15 | {
16 |
17 | public delegate void Delete(int index);
18 | public int Index;
19 | public Delete deleteEevnt { get; set; }
20 |
21 | public TaskJson.TaskItem taskItem;
22 | public TaskEditItem()
23 | {
24 | InitializeComponent();
25 | }
26 | public TaskEditItem(TaskJson.TaskItem taskItem)
27 | {
28 | this.taskItem = taskItem;
29 | InitializeComponent();
30 |
31 | }
32 | public void SetIndex(int index)
33 | {
34 | Index=index;
35 | this.label1.Text ="操作:"+ index.ToString();
36 | }
37 |
38 | public TaskJson.TaskItem GetTaskInfo()
39 | {
40 | return new TaskJson.TaskItem()
41 | {
42 | Oprate = ((TaskJson.OpType)this.select1.SelectedValue).Oprate,
43 | Param = input1.Text,
44 | IsAdb = ((TaskJson.OpType)this.select1.SelectedValue).IsAdb,
45 | };
46 |
47 | }
48 |
49 | public bool CheckValue()
50 | {
51 |
52 | return false;
53 | }
54 |
55 | private void TaskEditItem_Load(object sender, EventArgs e)
56 | {
57 | this.select1.Items = TaskJson.Configs;
58 | this.select1.SelectedIndex = 0;
59 |
60 | if (taskItem != null)
61 | {
62 | //this.label1.Text = "操作:" + Index;
63 | var d= TaskJson.OpTypes.Where(n => n.Oprate == taskItem.Oprate).FirstOrDefault();
64 | int i= TaskJson.OpTypes.IndexOf(d);
65 | if(i != -1)
66 | {
67 | this.select1.SelectedIndex = i;
68 | }
69 | this.input1.Text = taskItem.Param;
70 | }
71 |
72 | }
73 |
74 | private void select1_SelectedIndexChanged(object sender, int value)
75 | {
76 |
77 | }
78 |
79 | private void button1_Click(object sender, EventArgs e)
80 | {
81 | deleteEevnt(Index);
82 | this.Dispose();
83 |
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AutoTask/TaskList.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru.AutoTask
2 | {
3 | partial class TaskList
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.flowLayoutPanel1 = new AntdUI.In.FlowLayoutPanel();
32 | this.button1 = new AntdUI.Button();
33 | this.button2 = new AntdUI.Button();
34 | this.start_quatrz = new AntdUI.Button();
35 | this.shutdown = new AntdUI.Button();
36 | this.flowPanel1 = new AntdUI.FlowPanel();
37 | this.flowPanel1.SuspendLayout();
38 | this.SuspendLayout();
39 | //
40 | // flowLayoutPanel1
41 | //
42 | this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
43 | | System.Windows.Forms.AnchorStyles.Left)
44 | | System.Windows.Forms.AnchorStyles.Right)));
45 | this.flowLayoutPanel1.AutoScroll = true;
46 | this.flowLayoutPanel1.Location = new System.Drawing.Point(12, 52);
47 | this.flowLayoutPanel1.Name = "flowLayoutPanel1";
48 | this.flowLayoutPanel1.Size = new System.Drawing.Size(623, 433);
49 | this.flowLayoutPanel1.TabIndex = 0;
50 | //
51 | // button1
52 | //
53 | this.button1.Location = new System.Drawing.Point(3, 3);
54 | this.button1.Name = "button1";
55 | this.button1.Size = new System.Drawing.Size(75, 36);
56 | this.button1.TabIndex = 1;
57 | this.button1.Text = "添加任务";
58 | this.button1.Type = AntdUI.TTypeMini.Primary;
59 | this.button1.Click += new System.EventHandler(this.button1_Click);
60 | //
61 | // button2
62 | //
63 | this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
64 | this.button2.Location = new System.Drawing.Point(560, 12);
65 | this.button2.Name = "button2";
66 | this.button2.Size = new System.Drawing.Size(75, 34);
67 | this.button2.TabIndex = 2;
68 | this.button2.Text = "刷新";
69 | this.button2.Click += new System.EventHandler(this.button2_Click);
70 | //
71 | // start_quatrz
72 | //
73 | this.start_quatrz.Location = new System.Drawing.Point(165, 3);
74 | this.start_quatrz.Name = "start_quatrz";
75 | this.start_quatrz.Size = new System.Drawing.Size(75, 36);
76 | this.start_quatrz.TabIndex = 3;
77 | this.start_quatrz.Text = "开启任务";
78 | this.start_quatrz.Type = AntdUI.TTypeMini.Success;
79 | this.start_quatrz.Click += new System.EventHandler(this.button3_Click);
80 | //
81 | // shutdown
82 | //
83 | this.shutdown.Location = new System.Drawing.Point(84, 3);
84 | this.shutdown.Name = "shutdown";
85 | this.shutdown.Size = new System.Drawing.Size(75, 36);
86 | this.shutdown.TabIndex = 4;
87 | this.shutdown.Text = "关闭任务";
88 | this.shutdown.Type = AntdUI.TTypeMini.Error;
89 | this.shutdown.Click += new System.EventHandler(this.button4_Click);
90 | //
91 | // flowPanel1
92 | //
93 | this.flowPanel1.Controls.Add(this.start_quatrz);
94 | this.flowPanel1.Controls.Add(this.shutdown);
95 | this.flowPanel1.Controls.Add(this.button1);
96 | this.flowPanel1.Location = new System.Drawing.Point(12, 4);
97 | this.flowPanel1.Name = "flowPanel1";
98 | this.flowPanel1.Size = new System.Drawing.Size(260, 42);
99 | this.flowPanel1.TabIndex = 5;
100 | this.flowPanel1.Text = "flowPanel1";
101 | //
102 | // TaskList
103 | //
104 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
105 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
106 | this.ClientSize = new System.Drawing.Size(647, 497);
107 | this.Controls.Add(this.flowPanel1);
108 | this.Controls.Add(this.button2);
109 | this.Controls.Add(this.flowLayoutPanel1);
110 | this.Name = "TaskList";
111 | this.Text = "TaskList";
112 | this.Load += new System.EventHandler(this.TaskList_Load);
113 | this.flowPanel1.ResumeLayout(false);
114 | this.ResumeLayout(false);
115 |
116 | }
117 |
118 | #endregion
119 |
120 | private AntdUI.In.FlowLayoutPanel flowLayoutPanel1;
121 | private AntdUI.Button button1;
122 | private AntdUI.Button button2;
123 | private AntdUI.Button start_quatrz;
124 | private AntdUI.Button shutdown;
125 | private AntdUI.FlowPanel flowPanel1;
126 | }
127 | }
--------------------------------------------------------------------------------
/AutoTask/TaskList.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Tools;
2 | using Quartz;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Data;
7 | using System.Drawing;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 | using static MobileControlGuru.AutoTask.TaskJson;
13 |
14 | namespace MobileControlGuru.AutoTask
15 | {
16 | public partial class TaskList : BaseForm
17 | {
18 | public TaskList()
19 | {
20 | InitializeComponent();
21 | }
22 |
23 | private void TaskList_Load(object sender, EventArgs e)
24 | {
25 | Init();
26 | }
27 |
28 | public void Init()
29 | {
30 | TaskJson.LoadJsonData();
31 | this.flowLayoutPanel1.Controls.Clear();
32 | foreach (var task in TaskJson.Instance.tasks)
33 | {
34 | var item = new TaskShowItem(task);
35 | item.taskList = this;
36 | item.Tag = task;
37 |
38 | this.flowLayoutPanel1.Controls.Add(item);
39 | }
40 | start_quatrz.Visible = !QuartzJobUtil.scheduler.IsStarted;
41 | shutdown.Visible = QuartzJobUtil.scheduler.IsStarted;
42 |
43 |
44 | }
45 | private void button1_Click(object sender, EventArgs e)
46 | {
47 | ShowEdit(null);
48 | }
49 |
50 | private void EditFormClosed(object sender, FormClosedEventArgs e)
51 | {
52 | Init();
53 | }
54 |
55 | public void ShowEdit(TaskJson.TaskInfo taskinfo)
56 | {
57 | TaskEdit diglog = new TaskEdit(taskinfo);
58 | diglog.StartPosition = FormStartPosition.CenterParent;
59 | diglog.FormClosed += EditFormClosed;
60 | diglog.Show(this);
61 |
62 | }
63 |
64 | public void DelTask (int id)
65 | {
66 |
67 | TaskJson.DelTask(id);
68 | Init();
69 | }
70 |
71 | private void button2_Click(object sender, EventArgs e)
72 | {
73 | Init();
74 | }
75 |
76 | private void button3_Click(object sender, EventArgs e)
77 | {
78 | QuartzJobUtil.StartScheduler();
79 | foreach (var task in TaskJson.Instance.tasks)
80 | {
81 |
82 | try
83 | {
84 | Dictionary a = new Dictionary
85 | {
86 | {"taskInfo", task }
87 | };
88 | QuartzJobUtil.AddJob
89 | (task.id.ToString(), task.Corn, new JobDataMap(a));
90 |
91 | if (!task.IsRun)
92 | {
93 | QuartzJobUtil.PauseJob(task.id.ToString());
94 | }
95 |
96 | }
97 | catch (Exception ex) {
98 | LogHelper.Error(ex);
99 | MessageBox.Show($"添加任务{task.Name}出错 任务id:{task.id}");
100 | }
101 |
102 |
103 |
104 | }
105 |
106 | start_quatrz.Visible = false;
107 | shutdown.Visible = true;
108 |
109 | }
110 |
111 | private void button4_Click(object sender, EventArgs e)
112 | {
113 | QuartzJobUtil.ShutdownScheduler();
114 | start_quatrz.Visible = true;
115 | shutdown.Visible = false;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/AutoTask/TaskRun.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Base;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Threading;
9 | using MobileControlGuru.Tools;
10 | using MobileControlGuru.Src;
11 | using static MobileControlGuru.AutoTask.TaskRun;
12 | namespace MobileControlGuru.AutoTask
13 | {
14 | public class TaskRun
15 | {
16 | TaskJson.TaskInfo taskInfo;
17 | string DeviceName;
18 | bool Debug=false;
19 |
20 | public delegate void TaskStartDelegate();
21 | public delegate void TaskFinishedDelegate();
22 |
23 | public delegate void TaskSingleEndDelegate(string cmd);
24 | public delegate void TaskSingleStartDelegate(string cmd);
25 |
26 | //任务开始委托
27 | public TaskStartDelegate taskStartDelegate;
28 | //任务结束委托
29 | public TaskFinishedDelegate taskFinishedDelegate;
30 |
31 | //单条指令开始
32 | public TaskSingleStartDelegate singleStartDelegate;
33 | //单条指令结束
34 | public TaskSingleEndDelegate singleEndDelegate;
35 | public CancellationTokenSource cts = new CancellationTokenSource();
36 | public TaskRun(string deviceName, TaskJson.TaskInfo taskInfo, bool debug=false)
37 | {
38 | DeviceName = deviceName;
39 | this.taskInfo = taskInfo;
40 | Debug = debug;
41 | }
42 |
43 | ///
44 | /// 任务核心运行方法
45 | ///
46 | ///
47 | ///
48 | public string R(TaskJson.TaskItem taskItem)
49 | {
50 | try
51 | {
52 |
53 | if (singleStartDelegate != null)
54 | {
55 | singleStartDelegate(taskItem.Oprate + " " + taskItem.Param);
56 | }
57 |
58 | string res = "";
59 | if (taskItem.IsAdb)
60 | {
61 |
62 | var adb= ADB.Exec(
63 | (!string.IsNullOrEmpty(DeviceName)?"-s "+ DeviceName : "")+ " "
64 | +taskItem.Oprate + " " + taskItem.Param);
65 | res= adb.Message;
66 | }
67 | else
68 | {
69 | if (taskItem.Oprate == "sleep")
70 | {
71 | var times= taskItem.Param.Split(' ');
72 | if (times.Count() == 1)
73 | {
74 | Thread.Sleep(Convert.ToInt32(times[0]));
75 | }
76 | else
77 | {
78 | int time = new Random().Next(Convert.ToInt32(times[0]), Convert.ToInt32(times[1]));
79 | Thread.Sleep(time);
80 | }
81 |
82 | }
83 | else
84 | {
85 | res= CMD.Exec(taskItem.Param);
86 |
87 | }
88 | }
89 |
90 | if (singleEndDelegate != null)
91 | {
92 | singleEndDelegate(res);
93 | }
94 |
95 | return res;
96 | }
97 | catch (Exception ex)
98 | {
99 | LogHelper.Error(ex, taskItem.Oprate+""+ taskItem.Param);
100 | singleEndDelegate("run error"+ ex.Message);
101 | return ex.Message;
102 | }
103 |
104 |
105 | }
106 |
107 | public void Run()
108 | {
109 |
110 | if (taskStartDelegate != null)
111 | {
112 | taskStartDelegate();
113 | }
114 | if (Debug)
115 | {
116 | foreach (var t in taskInfo.TaskItems)
117 | {
118 | if (cts.Token.IsCancellationRequested)
119 | {
120 | break;
121 | }
122 | R(t);
123 | }
124 | }
125 | else
126 | {
127 | int i = taskInfo.RunTimes;
128 | while (i != 0)
129 | {
130 | foreach (var t in taskInfo.TaskItems)
131 | {
132 | if (cts.Token.IsCancellationRequested)
133 | {
134 | break;
135 | }
136 | R(t);
137 | }
138 | i--;
139 | }
140 |
141 | }
142 |
143 |
144 | if (taskFinishedDelegate != null)
145 | {
146 | taskFinishedDelegate();
147 | }
148 | }
149 |
150 | public async Task RunAsync()
151 | {
152 | //using (HttpClient client = new HttpClient())
153 | //{
154 | // string website = "https://www.example.com";
155 | // string content = await client.GetStringAsync(website);
156 | // Console.WriteLine("下载内容长度:" + content.Length);
157 | //}
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/AutoTask/TaskRunWindow.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru.AutoTask
2 | {
3 | partial class TaskRunWindow
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.button1 = new AntdUI.Button();
32 | this.textBox1 = new System.Windows.Forms.TextBox();
33 | this.button2 = new AntdUI.Button();
34 | this.flowLayoutPanel1 = new AntdUI.In.FlowLayoutPanel();
35 | this.flowLayoutPanel1.SuspendLayout();
36 | this.SuspendLayout();
37 | //
38 | // button1
39 | //
40 | this.button1.Location = new System.Drawing.Point(3, 3);
41 | this.button1.Name = "button1";
42 | this.button1.Size = new System.Drawing.Size(75, 38);
43 | this.button1.TabIndex = 1;
44 | this.button1.Text = "运行";
45 | this.button1.Click += new System.EventHandler(this.button1_Click);
46 | //
47 | // textBox1
48 | //
49 | this.textBox1.Location = new System.Drawing.Point(12, 54);
50 | this.textBox1.Multiline = true;
51 | this.textBox1.Name = "textBox1";
52 | this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
53 | this.textBox1.Size = new System.Drawing.Size(348, 469);
54 | this.textBox1.TabIndex = 2;
55 | //
56 | // button2
57 | //
58 | this.button2.Location = new System.Drawing.Point(84, 3);
59 | this.button2.Name = "button2";
60 | this.button2.Size = new System.Drawing.Size(75, 36);
61 | this.button2.TabIndex = 3;
62 | this.button2.Text = "停止";
63 | this.button2.Type = AntdUI.TTypeMini.Error;
64 | this.button2.Click += new System.EventHandler(this.button2_Click);
65 | //
66 | // flowLayoutPanel1
67 | //
68 | this.flowLayoutPanel1.Controls.Add(this.button1);
69 | this.flowLayoutPanel1.Controls.Add(this.button2);
70 | this.flowLayoutPanel1.Location = new System.Drawing.Point(12, 3);
71 | this.flowLayoutPanel1.Name = "flowLayoutPanel1";
72 | this.flowLayoutPanel1.Size = new System.Drawing.Size(200, 45);
73 | this.flowLayoutPanel1.TabIndex = 4;
74 | //
75 | // TaskRunWindow
76 | //
77 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
79 | this.ClientSize = new System.Drawing.Size(371, 532);
80 | this.Controls.Add(this.flowLayoutPanel1);
81 | this.Controls.Add(this.textBox1);
82 | this.Name = "TaskRunWindow";
83 | this.Text = "t";
84 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.TaskRunWindow_FormClosing);
85 | this.Load += new System.EventHandler(this.TaskRunWindow_Load);
86 | this.flowLayoutPanel1.ResumeLayout(false);
87 | this.ResumeLayout(false);
88 | this.PerformLayout();
89 |
90 | }
91 |
92 | #endregion
93 | private AntdUI.Button button1;
94 | private System.Windows.Forms.TextBox textBox1;
95 | private AntdUI.Button button2;
96 | private AntdUI.In.FlowLayoutPanel flowLayoutPanel1;
97 | }
98 | }
--------------------------------------------------------------------------------
/AutoTask/TaskRunWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 | using static Microsoft.WindowsAPICodePack.Shell.PropertySystem.SystemProperties.System;
12 | using static MobileControlGuru.AutoTask.TaskRun;
13 |
14 | namespace MobileControlGuru.AutoTask
15 | {
16 | public partial class TaskRunWindow : BaseForm
17 | {
18 | public string DeviceName;
19 | public TaskJson.TaskInfo TaskInfo;
20 | public TaskRun taskRun;
21 | bool Debug=false;
22 | public System.Threading.Tasks.Task task;
23 |
24 | //任务开始委托
25 | public TaskStartDelegate taskStartDelegate;
26 | //任务结束委托
27 | public TaskFinishedDelegate taskFinishedDelegate;
28 |
29 | //单条指令开始
30 | public TaskSingleStartDelegate singleStartDelegate;
31 | //单条指令结束
32 | public TaskSingleEndDelegate singleEndDelegate;
33 |
34 | public TaskRunWindow( TaskJson.TaskInfo taskInfo, bool debug=false)
35 | {
36 | DeviceName = taskInfo.DeviceName;
37 | TaskInfo = taskInfo;
38 | Debug = debug;
39 | InitializeComponent();
40 |
41 | }
42 |
43 | public void RunTask()
44 | {
45 | taskRun = new TaskRun(DeviceName, TaskInfo, Debug);
46 | taskRun.singleStartDelegate += TaskItemStart;
47 | taskRun.singleEndDelegate += TaskItemEnd;
48 | taskRun.taskStartDelegate += TaskStart;
49 | taskRun.taskFinishedDelegate += TaskFinished;
50 |
51 | taskRun.taskStartDelegate += taskStartDelegate;
52 | taskRun.taskFinishedDelegate += taskFinishedDelegate;
53 | taskRun.singleStartDelegate += singleStartDelegate;
54 | taskRun.singleEndDelegate += singleEndDelegate;
55 |
56 | task = new System.Threading.Tasks.Task(() =>
57 | {
58 |
59 | taskRun.Run();
60 |
61 | }, taskRun.cts.Token);
62 | task.Start();
63 |
64 | }
65 |
66 | private void TaskStart()
67 | {
68 |
69 | UpdateButtonStart(false);
70 | UpdateButtonEnd(true);
71 | AddMessage("task Start :"+DateTime.Now.ToString());
72 | }
73 |
74 | private void TaskFinished()
75 | {
76 | UpdateButtonStart(true);
77 | UpdateButtonEnd( false);
78 | AddMessage("task End :"+ DateTime.Now.ToString());
79 | }
80 | private void UpdateButtonStart(bool visible)
81 | {
82 | if (button1.InvokeRequired)
83 | {
84 | button1.Invoke(new Action(() =>
85 | {
86 | this.button1.Visible = visible;
87 |
88 | }));
89 | }
90 | else
91 | {
92 | this.button1.Visible = visible;
93 | }
94 | }
95 |
96 | private void UpdateButtonEnd(bool visible)
97 | {
98 | if (button2.InvokeRequired)
99 | {
100 | button2.Invoke(new Action(() =>
101 | {
102 | this.button2.Visible = visible;
103 |
104 | }));
105 | }
106 | else
107 | {
108 | this.button2.Visible = visible;
109 | }
110 | }
111 |
112 | private void TaskItemEnd(string output)
113 | {
114 | AddMessage("output:"+output);
115 |
116 | }
117 |
118 | private void TaskItemStart(string cmd)
119 | {
120 | AddMessage("cmd:" + cmd);
121 | // throw new NotImplementedException();
122 | }
123 |
124 | public void AddMessage(string msg)
125 | {
126 |
127 | // 假设这是你在后台线程中执行的代码
128 | if (textBox1.InvokeRequired)
129 | {
130 | textBox1.Invoke(new Action(() =>
131 | {
132 | this.textBox1.Text += msg + Environment.NewLine;
133 | this.textBox1.Refresh();
134 | textBox1.SelectionStart = textBox1.Text.Length; // 设置选区开始位置为文本末尾
135 | textBox1.ScrollToCaret(); // 滚动到插入符号位置(即文本末尾)
136 | }));
137 | }
138 | else
139 | {
140 | // 如果当前线程已经是UI线程,则直接更新
141 | this.textBox1.Text += msg + Environment.NewLine;
142 | this.textBox1.Refresh();
143 | textBox1.SelectionStart = textBox1.Text.Length; // 设置选区开始位置为文本末尾
144 | textBox1.ScrollToCaret(); // 滚动到插入符号位置(即文本末尾)
145 | }
146 | }
147 |
148 | private void button1_Click(object sender, EventArgs e)
149 | {
150 | RunTask();
151 | }
152 |
153 | private void TaskRunWindow_Load(object sender, EventArgs e)
154 | {
155 |
156 | }
157 |
158 | private void TaskRunWindow_FormClosing(object sender, FormClosingEventArgs e)
159 | {
160 |
161 | }
162 |
163 | private void button2_Click(object sender, EventArgs e)
164 | {
165 | //task.ki();
166 | taskRun.cts.Cancel();
167 | //TaskFinished();
168 | }
169 |
170 |
171 |
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/AutoTask/TaskShowItem.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Src;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Data;
7 | using System.Drawing;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading;
11 | using System.Threading.Tasks;
12 | using System.Windows.Forms;
13 |
14 | namespace MobileControlGuru.AutoTask
15 | {
16 | public partial class TaskShowItem : UserControl
17 | {
18 | public TaskShowItem()
19 | {
20 | InitializeComponent();
21 | }
22 | public TaskJson.TaskInfo taskInfo;
23 | public TaskList taskList;
24 | TaskRunWindow runWindow;
25 |
26 | public TaskShowItem(TaskJson.TaskInfo taskInfo)
27 | {
28 | this.taskInfo = taskInfo;
29 | InitializeComponent();
30 | }
31 |
32 | private void TaskShowItem_Load(object sender, EventArgs e)
33 | {
34 | if (taskInfo != null)
35 | {
36 | this.label1.Text = taskInfo.Name;
37 | this.inputNumber1.Value=taskInfo.RunTimes;
38 |
39 | run_able.Text = taskInfo.IsRun?"启用中":"禁用中";
40 | run_able.Type = taskInfo.IsRun ? AntdUI.TTypeMini.Success: AntdUI.TTypeMini.Warn;
41 | }
42 |
43 |
44 | }
45 |
46 | private void button1_Click(object sender, EventArgs e)
47 | {
48 | var taskinfo= (TaskJson.TaskInfo)this.Tag;
49 |
50 | taskList.ShowEdit(taskinfo);
51 | }
52 |
53 | private void button2_Click(object sender, EventArgs e)
54 | {
55 | var taskinfo = (TaskJson.TaskInfo)this.Tag;
56 | DialogResult AF = MessageBox.Show("确定删除"+ taskinfo.Name+ "任务吗?", "确认框", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
57 | if (AF == DialogResult.OK)
58 | {
59 | taskList.DelTask(taskinfo.id);
60 | }
61 | else
62 | {
63 |
64 | }
65 |
66 | }
67 |
68 | private void button3_Click(object sender, EventArgs e)
69 | {
70 |
71 | //AntdUI.Button button = (AntdUI.Button)sender;
72 |
73 | //DeviceManager.Instance.devices.ForEach(n =>
74 | //{
75 |
76 |
77 | //});
78 | runWindow = new TaskRunWindow(taskInfo);
79 | runWindow.Show();
80 | //button.Visible = false;
81 | //runWindow.taskStartDelegate += taskStart;
82 | //runWindow.taskFinishedDelegate += taskFinished;
83 | runWindow.RunTask();
84 | }
85 |
86 | private void taskStart()
87 | {
88 | UpdateButton(run, false);
89 | UpdateButton(del, false);
90 | UpdateButton(edit, false);
91 |
92 | UpdateButton(button4, true);
93 | UpdateButton(run_able, true);
94 | }
95 |
96 | private void taskFinished()
97 | {
98 | UpdateButton(run,true);
99 | UpdateButton(del,true);
100 | UpdateButton(edit,true);
101 |
102 | UpdateButton(button4,false);
103 | UpdateButton(run_able, false);
104 |
105 | runWindow=null;
106 | }
107 |
108 | private void UpdateButton(AntdUI.Button button, bool visible)
109 | {
110 | if (button.InvokeRequired)
111 | {
112 | button.Invoke(new Action(() =>
113 | {
114 | button.Visible = visible;
115 |
116 | }));
117 | }
118 | else
119 | {
120 | button.Visible = visible;
121 | }
122 | }
123 |
124 | private void inputNumber1_ValueChanged(object sender, decimal value)
125 | {
126 | taskInfo.RunTimes=Convert.ToInt32(value);
127 | TaskJson.EditTask(taskInfo);
128 | }
129 |
130 | private void button4_Click(object sender, EventArgs e)
131 | {
132 | runWindow.Show();
133 | }
134 |
135 | private void button5_Click(object sender, EventArgs e)
136 | {
137 | //runWindow.taskRun.cts.Cancel();
138 |
139 | var btn = (AntdUI.Button)sender;
140 | this.taskInfo.IsRun = !taskInfo.IsRun;
141 |
142 | if (taskInfo.IsRun)
143 | {
144 | btn.Text = "启用中";
145 | btn.Type = AntdUI.TTypeMini.Success;
146 |
147 | QuartzJobUtil.ResumeJob(taskInfo.id.ToString());
148 | }
149 | else
150 | {
151 | btn.Text = "禁用中";
152 | btn.Type = AntdUI.TTypeMini.Warn;
153 | QuartzJobUtil.PauseJob(taskInfo.id.ToString());
154 | }
155 | TaskJson.EditTask(taskInfo);
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Base/ADB.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Src;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Drawing;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading;
11 | using System.Threading.Tasks;
12 |
13 | namespace MobileControlGuru.Base
14 | {
15 | public class ADB
16 | {
17 |
18 | public static string ADB_PATH = Path.Combine(ConfigHelp.GetConfig("ScrcpyPath"), "adb.exe");
19 |
20 | public static AdbParse Exec(string Arguments)
21 | {
22 | try
23 | {
24 | LogHelper.Info("exc [adb " + Arguments+"]");
25 | var p = Process.Start(new System.Diagnostics.ProcessStartInfo(ADB_PATH)
26 | {
27 | Arguments = Arguments,
28 | CreateNoWindow = true,
29 | UseShellExecute = false,
30 | RedirectStandardOutput = true,
31 | RedirectStandardError = true,
32 | StandardOutputEncoding = Encoding.UTF8,
33 | StandardErrorEncoding = Encoding.UTF8,
34 | });
35 |
36 | string output = p.StandardOutput.ReadToEnd();
37 | LogHelper.Info("adb output: " + output);
38 |
39 | p.Close();
40 | p.Dispose();
41 | return new AdbParse("adb "+ Arguments, output);
42 | }
43 | catch(Exception e)
44 | {
45 | LogHelper.Error(e, "exc error:[adb " + Arguments + "]\n");
46 | return new AdbParse("adb " + Arguments, false,e.Message);
47 |
48 | }
49 |
50 |
51 |
52 | }
53 |
54 | public async Task ExecuteCommandsInParallel(List commands)
55 | {
56 | var tasks = new List();
57 |
58 | foreach (var command in commands)
59 | {
60 | // 创建并启动一个新的任务,传入当前命令
61 | tasks.Add(Task.Run(() => Exec(command)));
62 | }
63 |
64 | // 等待所有任务完成
65 | await Task.WhenAll(tasks);
66 | }
67 |
68 |
69 |
70 |
71 | #region adb 操作
72 |
73 | public static AdbParse Connect(string device)
74 | {
75 |
76 | var res = Exec($"connect {device}");
77 |
78 | DeviceManager.Instance.UpdateDevices();
79 | return res;
80 | }
81 |
82 | public static AdbParse Pair(string device,int port,int code)
83 | {
84 |
85 | var res = Exec($"pair {device}:{port} {code}");
86 | DeviceManager.Instance.UpdateDevices();
87 | return res;
88 | }
89 | public static AdbParse SendKeyEvent(string device, ADBKey.Key key)
90 | {
91 |
92 | var res = Exec($"-s {device} shell input keyevent {key}");
93 | return res;
94 | }
95 | public static AdbParse SendKeyEvent(string device, string key)
96 | {
97 |
98 | var res = Exec($"-s {device} shell input keyevent {key}");
99 | return res;
100 |
101 | }
102 | public static AdbParse Screencap(string device, string path)
103 | {
104 |
105 | var res = Exec($"-s {device} shell screencap -p >{path}");
106 | return res;
107 |
108 | }
109 |
110 | #endregion
111 | public static List GetDeiveces()
112 | {
113 | var str = Exec("devices");
114 | var devices = str.Message.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
115 | .Skip(1).Select(line => line.Split('\t')).ToArray();
116 | List items = new List();
117 | foreach (var deviceInfo in devices)
118 | {
119 | if (deviceInfo.Length == 2)
120 | {
121 | string deviceId = deviceInfo[0];
122 | string deviceStatus = deviceInfo[1];
123 | items.Add(new Model.Device()
124 | {
125 | Name = deviceId,
126 | Status = deviceStatus,
127 | IsTcpIP= Tools.Common.IsValidIP(deviceId)
128 |
129 | });
130 | }
131 | }
132 | items= items.Where(n=>n.Status=="device").ToList();
133 | return items;
134 | }
135 |
136 | public static async Task Lock(List deviceItems)
137 | {
138 |
139 |
140 | var tasks = new List();
141 | foreach (var d in deviceItems)
142 | {
143 | // 创建并启动一个新的任务,传入当前命令
144 | tasks.Add(Task.Run(
145 | () =>new DeviceADB(d.Name).SendKeyEvent( ADBKey.Key.KEYCODE_POWER)
146 | )
147 | );
148 | }
149 |
150 | // 等待所有任务完成
151 | await Task.WhenAll(tasks);
152 |
153 | }
154 |
155 | public static void Lock(string device)
156 | {
157 | new DeviceADB(device).SendKeyEvent(ADBKey.Key.KEYCODE_POWER);
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/Base/ADBKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MobileControlGuru.Base
8 | {
9 | public class ADBKey
10 | {
11 | //https://blog.csdn.net/h_bpdwn/article/details/91425599
12 | public enum Key
13 | {
14 |
15 | KEYCODE_HOME=3,
16 | KEYCODE_MENU=82,
17 | KEYCODE_BACK=4,
18 |
19 | KEYCODE_VOLUME_UP = 24,
20 | KEYCODE_VOLUME_DOWN = 25,
21 | KEYCODE_POWER = 26,
22 |
23 | KEYCODE_ENTER = 66,
24 | KEYCODE_ESCAPE = 111,
25 |
26 | KEYCODE_VOLUME_MUTE = 164,
27 | KEYCODE_PAGE_UP = 92,
28 | KEYCODE_PAGE_DOWN = 93,
29 |
30 |
31 | #region MEDIA
32 | KEYCODE_MEDIA_PLAY,
33 | KEYCODE_MEDIA_PAUSE,
34 | KEYCODE_MEDIA_STOP,
35 | KEYCODE_MEDIA_PLAY_PAUSE,
36 | KEYCODE_MEDIA_FAST_FORWARD,
37 | KEYCODE_MEDIA_REWIND,
38 | KEYCODE_MEDIA_NEXT,
39 | KEYCODE_MEDIA_PREVIOUS,
40 | KEYCODE_MEDIA_CLOSE,
41 | KEYCODE_MEDIA_EJECT,
42 | KEYCODE_MEDIA_RECORD,
43 | #endregion
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Base/AdbParse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MobileControlGuru.Base
8 | {
9 | ///
10 | /// adb 返回处理
11 | ///
12 | public class AdbParse
13 | {
14 | public bool IsSuccess { get; set; }
15 | public string Message { set; get; }
16 | public string Cmd { set; get; }
17 |
18 | public AdbParse(string Cmd, string adbres)
19 | {
20 | this.Message= adbres;
21 | this.Cmd = Cmd;
22 | this.IsSuccess = true;
23 |
24 |
25 | }
26 |
27 | public AdbParse(string Cmd, bool isSuccess, string message)
28 | {
29 | IsSuccess = isSuccess;
30 | Message = message;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Base/CMD.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Tools;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MobileControlGuru.Base
10 | {
11 | public class CMD
12 | {
13 |
14 | public static string Exec(string command) {
15 |
16 | LogHelper.Info("cmd run:" + command);
17 | // 创建一个新的ProcessStartInfo对象来配置进程启动信息
18 | ProcessStartInfo startInfo = new ProcessStartInfo();
19 | startInfo.FileName = "cmd.exe"; // 指定要运行的命令解释器(CMD)
20 | startInfo.Arguments = "/C " + command; // 指定要运行的命令和参数(/C 表示执行完命令后关闭命令窗口)
21 | startInfo.RedirectStandardOutput = true; // 重定向标准输出以便捕获输出
22 | startInfo.UseShellExecute = false; // 设置为false以便能够重定向输出
23 | startInfo.CreateNoWindow = true; // 设置为true以隐藏命令窗口(如果不需要看到窗口)
24 |
25 | // 使用ProcessStartInfo对象启动进程
26 | using (Process process = new Process { StartInfo = startInfo })
27 | {
28 | // 启动进程
29 | process.Start();
30 |
31 | // 读取命令的输出
32 | string output = process.StandardOutput.ReadToEnd();
33 |
34 | // 等待进程结束
35 | process.WaitForExit();
36 | LogHelper.Info("cmd output:" + output);
37 | return output;
38 | }
39 |
40 |
41 |
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Base/FireWallHelper.cs:
--------------------------------------------------------------------------------
1 | using NetFwTypeLib;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MobileControlGuru.Base
11 | {
12 | public class FireWallHelper
13 | {
14 | public static void AddOrUpdateInboundRule(string name, int port)
15 | {
16 | // 获取防火墙策略对象
17 | INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
18 |
19 | // 检查规则是否存在
20 | INetFwRule existingRule = firewallPolicy.Rules.Item(name);
21 | if (existingRule != null)
22 | {
23 | // 更新现有规则
24 | existingRule.LocalPorts = port.ToString();
25 | // 你可以根据需要更新其他属性,比如 Action, Enabled 等
26 |
27 | }
28 | else
29 | {
30 | // 创建新规则
31 | INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwRule"));
32 |
33 | // 设置规则属性
34 | firewallRule.Name = name;
35 | firewallRule.Description = "Allow inbound traffic to my service on port " + port;
36 | firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
37 | firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
38 | firewallRule.Enabled = true;
39 | firewallRule.Profiles = (int)(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_ALL);
40 | firewallRule.LocalPorts = port.ToString();
41 | firewallRule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
42 | firewallRule.Grouping = "@firewallapi.dll,-28752"; // 可以自定义分组,或者留空
43 | firewallRule.EdgeTraversal = false;
44 |
45 | // 添加新规则到防火墙策略
46 | firewallPolicy.Rules.Add(firewallRule);
47 |
48 | }
49 | }
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Base/GlobalHotkey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows.Forms;
9 |
10 | namespace MobileControlGuru.Base
11 | {
12 | public class GlobalHotkey
13 | {
14 | #region Hotkey
15 | //如果函数执行成功,返回值不为0。
16 | //如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。
17 | [DllImport("user32.dll", SetLastError = true)]
18 | public static extern bool RegisterHotKey(
19 | IntPtr hWnd, //要定义热键的窗口的句柄
20 | int id, //定义热键ID(不能与其它ID重复)
21 | KeyModifiers fsModifiers, //标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效
22 | Keys vk //定义热键的内容
23 | );
24 | [DllImport("user32.dll", SetLastError = true)]
25 | public static extern bool UnregisterHotKey(
26 | IntPtr hWnd, //要取消热键的窗口的句柄
27 | int id //要取消热键的ID
28 | );
29 | //定义了辅助键的名称(将数字转变为字符以便于记忆,也可去除此枚举而直接使用数值)
30 | [Flags()]
31 | public enum KeyModifiers
32 | {
33 | None = 0,
34 | Alt = 1,
35 | Ctrl = 2,
36 | Shift = 4,
37 | WindowsKey = 8
38 | }
39 | #endregion
40 |
41 |
42 |
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Base/ProcessWindowController.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Model;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 |
11 | namespace MobileControlGuru.Base
12 | {
13 | public class ProcessWindowController
14 | {
15 | [DllImport("user32.dll")]
16 | public static extern bool SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
17 | [DllImport("user32.dll")]
18 | public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
19 | [DllImport("user32.dll")]
20 | public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
21 |
22 | [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
23 | public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
24 | [DllImport("user32.dll")]
25 | public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
26 |
27 | [DllImport("user32.dll")]
28 | public static extern int GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
29 |
30 | [DllImport("user32.dll")]
31 | [return: MarshalAs(UnmanagedType.Bool)]
32 | public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
33 |
34 | [DllImport("user32.dll")]
35 | public static extern bool UnhookWinEvent(IntPtr hWinEventHook);
36 | [StructLayout(LayoutKind.Sequential)]
37 | public struct RECT
38 | {
39 | public int Left; //最左坐标
40 | public int Top; //最上坐标
41 | public int Right; //最右坐标
42 | public int Bottom; //最下坐标
43 | }
44 |
45 | public const uint WINEVENT_OUTOFCONTEXT = 0;
46 | public const uint EVENT_SYSTEM_FOREGROUND = 3;
47 | public const int SW_MINIMIZE = 6;
48 | public const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
49 | public const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;
50 |
51 | public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
52 |
53 |
54 |
55 |
56 | public static void MinimizeProcessWindow(int processId)
57 | {
58 | // 获取进程的主窗口句柄
59 | IntPtr hWnd = Process.GetProcessById(processId).MainWindowHandle;
60 |
61 | // 如果找到了窗口句柄
62 | if (hWnd != IntPtr.Zero)
63 | {
64 | // 将窗口最小化
65 | ShowWindow(hWnd, SW_MINIMIZE);
66 | }
67 | else
68 | {
69 | Console.WriteLine($"无法找到进程ID {processId} 的主窗口");
70 | }
71 | }
72 | public static string GetWindowTitle(int processId)
73 | {
74 | // 获取进程的主窗口句柄
75 | IntPtr hWnd = Process.GetProcessById(processId).MainWindowHandle;
76 |
77 | // 创建一个StringBuilder来存储窗口标题
78 | var sb = new StringBuilder(256);
79 |
80 | // 如果找到了窗口句柄
81 | if (hWnd != IntPtr.Zero)
82 | {
83 | // 获取窗口标题
84 | int length = GetWindowText(hWnd, sb, sb.Capacity);
85 | if (length > 0)
86 | {
87 | return sb.ToString();
88 | }
89 | else
90 | {
91 | Console.WriteLine("无法获取窗口标题");
92 | }
93 | }
94 | else
95 | {
96 | Console.WriteLine($"无法找到进程ID {processId} 的主窗口");
97 | }
98 |
99 | return null;
100 | }
101 |
102 |
103 |
104 |
105 |
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Base/Scrcpy.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Tools;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MobileControlGuru.Base
11 | {
12 | public class Scrcpy
13 | {
14 | public static string PATH = Path.Combine(ConfigHelp.GetConfig("ScrcpyPath"), "scrcpy.exe");
15 |
16 | public static bool ChcekScrcpyPATH()
17 | {
18 |
19 | return File.Exists(PATH);
20 | }
21 | public static void ExtractScrcpyZip(string BasePath)
22 | {
23 |
24 | ZipHelper.ExtractZipToDirectory(BasePath);
25 | string basapath = Path.Combine(BasePath, "scrcpy-win64-v2.4");
26 | Tools.ConfigHelp.SetSetting("ScrcpyPath", basapath);
27 | ADB.ADB_PATH = Path.Combine(basapath, "adb.exe");
28 | Scrcpy.PATH = Path.Combine(basapath, "scrcpy.exe");
29 | }
30 |
31 | public static Process Exec(string Arguments)
32 | {
33 | LogHelper.Info("exc [scrcpy " + Arguments+"]");
34 | var p = Process.Start(new System.Diagnostics.ProcessStartInfo(PATH)
35 | {
36 | Arguments = Arguments,
37 | CreateNoWindow = true,
38 | UseShellExecute = false,
39 | RedirectStandardOutput = true,
40 | RedirectStandardError = true,
41 | StandardOutputEncoding = Encoding.UTF8,
42 | StandardErrorEncoding = Encoding.UTF8,
43 | });
44 | p.EnableRaisingEvents = true;
45 | return p;
46 | }
47 |
48 | #region
49 | public static Process IPConnet(string device,string port)
50 | {
51 | string device_ip = $"{device}:{port}";
52 | var p= IPPut(device_ip);
53 | return p;
54 | }
55 | public static Process IPPut(string device_ip)
56 | {
57 | var adbinfo = ADB.Connect(device_ip);
58 | var p = Exec($"-s {device_ip} --window-title={device_ip} "+Scrcpy.GetDefaultSetting());
59 | return p;
60 | }
61 |
62 |
63 | public static Process UsbPut(string device)
64 | {
65 | var p = Exec($" -s {device} --window-title={device} " + Scrcpy.GetDefaultSetting());
66 | return p;
67 | }
68 |
69 | public static Process Put(string device,string CustomSetting="")
70 | {
71 | Process p = null;
72 | if (!string.IsNullOrEmpty(CustomSetting))
73 | {
74 | p = Exec($" -s {device} --window-title={device} " + CustomSetting);
75 | }
76 | else
77 | {
78 | p = Exec($" -s {device} --window-title={device} " + Scrcpy.GetDefaultSetting());
79 | }
80 |
81 | return p;
82 | }
83 | #endregion
84 |
85 |
86 | public static string GetDefaultSetting()
87 | {
88 | var scrcpyParam = JsonHelp.Str2Obj(ConfigHelp.GetConfig("ScrcpyParamObj"));
89 |
90 | if (scrcpyParam != null)
91 | {
92 | return scrcpyParam.ToString();
93 | }
94 |
95 | return "";
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Base/ScrcpyParam.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MobileControlGuru.Base
9 | {
10 | public class ScrcpyParam
11 | {
12 | #region audio params
13 | [ScrcpyParam("--no-audio")]
14 | public bool NoAudio { get; set; }
15 |
16 |
17 |
18 | #endregion
19 |
20 | #region video params https://github.com/Genymobile/scrcpy/blob/master/doc/video.md
21 | [ScrcpyParam("--no-video")]
22 | public bool NoVideo { get; set; }
23 |
24 | #endregion
25 |
26 |
27 | #region window params https://github.com/Genymobile/scrcpy/blob/master/doc/window.md
28 | //[ScrcpyParam("--window-title")]
29 | //public string WindowTitle { get; set; }
30 | [ScrcpyParam("--window-x")]
31 | public string WindowX { get; set; }
32 | [ScrcpyParam("--window-y")]
33 | public string WindowY { get; set; }
34 | [ScrcpyParam("--window-width")]
35 | public string WindowWidth { get; set; }
36 | [ScrcpyParam("--window-height")]
37 | public string WindowHeight { get; set; }
38 |
39 | [ScrcpyParam("--window-borderless")]
40 | public bool WindowBorderless { get; set; }
41 |
42 | [ScrcpyParam("--always-on-top")]
43 | public bool AlwaysOnTop { get; set; }
44 | [ScrcpyParam("--fullscreen")]
45 | public bool Fullscreen { get; set; }
46 | [ScrcpyParam("--disable-screensaver")]
47 | public bool DisableScreensaver { get; set; }
48 |
49 |
50 | #endregion
51 |
52 |
53 | #region
54 | [ScrcpyParam("--keyboard=uhid")]
55 | public bool KeyboardUhid { get; set; }
56 | [ScrcpyParam("--stay-awake")]
57 | public bool StayAwake { get; set; }
58 | [ScrcpyParam("--turn-screen-off")]
59 | public bool TurnScreenOff { get; set; }
60 | #endregion
61 |
62 | public override string ToString()
63 | {
64 | StringBuilder sb = new StringBuilder();
65 | var properties = typeof(ScrcpyParam).GetProperties();
66 |
67 | foreach (var property in properties)
68 | {
69 | Type propertyType = property.PropertyType;
70 |
71 | ScrcpyParamAttribute attr = property.GetCustomAttribute();
72 |
73 | switch (propertyType.Name)
74 | {
75 | case "Boolean":
76 | if (((bool)property.GetValue(this))) {
77 | sb.Append($" {attr.ParamName}");
78 | }
79 | break;
80 | case "String":
81 | if (!string.IsNullOrEmpty(property.GetValue(this).ToString())) {
82 | sb.Append($" {attr.ParamName}{attr.ValueSymbol}{property.GetValue(this)}");
83 | }
84 | break;
85 | default:
86 |
87 | break;
88 | }
89 |
90 | }
91 |
92 | return sb.ToString();
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Base/ScrcpyParamAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MobileControlGuru.Base
8 | {
9 | public class ScrcpyParamAttribute : Attribute
10 | {
11 | public string ParamName { get; set; }
12 | public string ValueSymbol { get; set; }
13 |
14 | public ScrcpyParamAttribute(string paramName, string valueSymbol="=")
15 | {
16 | ParamName = paramName;
17 | ValueSymbol = valueSymbol;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/BaseControl.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class BaseControl
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region 组件设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.SuspendLayout();
32 | //
33 | // BaseControl
34 | //
35 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
36 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
37 | this.Name = "BaseControl";
38 | this.Size = new System.Drawing.Size(305, 50);
39 | this.Load += new System.EventHandler(this.BaseControl_Load);
40 | this.ResumeLayout(false);
41 |
42 | }
43 |
44 | #endregion
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/BaseControl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace MobileControlGuru
13 | {
14 | public partial class BaseControl : UserControl
15 | {
16 |
17 | public ComponentResourceManager resources;
18 | public BaseControl()
19 | {
20 | InitializeComponent();
21 | }
22 |
23 | public void ChangeLang(string lang)
24 | {
25 | Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang);
26 |
27 | }
28 | public void ApplyResource()
29 | {
30 | foreach (Control ctl in this.Controls)
31 | {
32 | resources.ApplyResources(ctl, ctl.Name);
33 | }
34 | this.ResumeLayout(false);
35 | this.PerformLayout();
36 | resources.ApplyResources(this, "$this");
37 | }
38 |
39 | private void BaseControl_Load(object sender, EventArgs e)
40 | {
41 | var lang = Tools.ConfigHelp.GetConfig("Lang");
42 | if (!string.IsNullOrEmpty(lang))
43 | {
44 | ChangeLang(lang);
45 | ApplyResource();
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/BaseControl.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/BaseForm.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Properties;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace MobileControlGuru
12 | {
13 | public class BaseForm : Form
14 | {
15 | public ComponentResourceManager resources;
16 | public BaseForm()
17 | {
18 | //resources = new ComponentResourceManager();
19 | }
20 |
21 | public void ChangeLang(string lang)
22 | {
23 | Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang);
24 |
25 | }
26 |
27 | private void InitializeComponent()
28 | {
29 | this.SuspendLayout();
30 | //
31 | // BaseForm
32 | //
33 | this.ClientSize = new System.Drawing.Size(284, 261);
34 | this.Name = "BaseForm";
35 | this.Load += new System.EventHandler(this.BaseForm_Load);
36 | this.ResumeLayout(false);
37 |
38 | }
39 |
40 | private void BaseForm_Load(object sender, EventArgs e)
41 | {
42 |
43 | }
44 |
45 | public void ApplyResource()
46 | {
47 | //foreach (Control ctl in this.Controls)
48 | //{
49 | // resources.ApplyResources(ctl, ctl.Name);
50 |
51 | // if (ctl.Controls.Count>0 )
52 | // {
53 |
54 |
55 | // }
56 | //}
57 | Apply(this.Controls);
58 | this.ResumeLayout(false);
59 | this.PerformLayout();
60 | resources.ApplyResources(this, "$this");
61 |
62 | }
63 |
64 |
65 | public void Apply(Control.ControlCollection controls)
66 | {
67 | foreach (Control ctl in controls)
68 | {
69 | resources.ApplyResources(ctl, ctl.Name);
70 | if(ctl.Controls.Count>0)
71 | {
72 | Apply(ctl.Controls);
73 | }
74 |
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/BaseForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/Docs/Task.md:
--------------------------------------------------------------------------------
1 | # 任务说明
2 | 通过corn表达式来进行任务调度
3 | 多任务尚未测试,如果bug及时反馈
4 |
5 | # 操作说明
6 | 1. 进入任务列表
7 | 2. 编辑任务信息
8 | 3. 开启任务(默认启动都要手动开启)
9 | 4. 任务保存在程序目录中的 task.json
10 |
11 | # 操作和参数
12 |
13 | | 操作 | 参数示例| 备注 |
14 | | --- | --- | --- |
15 | | 点击 | 500 500| 输入 x y 坐标,坐标可通过调试打开显示坐标显示,有些手机需要开启模拟点击才能运行 |
16 | | 滑动 | 540 1300 540 500 1000 | 5个数字,表示从哪里滑动到哪里, 最后一个是时间,时间越长滑动越慢 |
17 | | 按键 | KEYCODE_HOME(或3) |字符或者数字 可搜索安卓keyevent 找到对应的键码 |
18 | | 启动APP | com.alibaba.android.rimet/com.alibaba.android.rimet.biz.LaunchHomeActivity | 启动app需要获取到app的Activity 自行搜索 安卓启动xxx app |
19 | | 睡眠 | 500 1500(或 500) | 单位毫秒 填一个数字就是固定睡眠,两个数字,随机在两个值之间时长 |
20 | | 自定义命令 | 无 | 自定义cmd指令,可以运行控制台执行 |
21 |
22 | # corn表达式
23 | 自行搜索corn表达式
24 |
25 | # 任务示例
26 | ```json
27 | [
28 | {
29 | "Name": "每5秒下滑",
30 | "TaskItems": [
31 | {
32 | "Oprate": "shell input swipe",
33 | "Param": "540 1300 540 500 1000",
34 | "IsAdb": true
35 | }
36 | ],
37 | "id": 1,
38 | "RunTimes": 1,
39 | "DeviceName": "419218f7",
40 | "Corn": "0/5 * * * * ?",
41 | "IsRun": true
42 | }
43 | ]
44 | ```
45 |
46 | ## 界面预览
47 |
48 | 任务列表
49 |
50 | 
51 |
52 | 任务编辑
53 |
54 | 
--------------------------------------------------------------------------------
/Docs/Update.en.md:
--------------------------------------------------------------------------------
1 | # Update Log
2 |
3 | ## V 1.1
4 | 1. Add automated tasks
5 |
6 |
7 | ## V 1.0.8.1
8 | 1. Add window top and screen top
9 |
10 | ## V 1.0.8.0
11 | 1. Add the function of custom shortcut keys (the entry is set icon in the upper right corner)
12 | 2. Add wireless authorization (not via usb authorization)
13 | 3. Add wireless authorization API
14 |
15 |
16 | ## V 1.0.7
17 | 1. Add English support
18 |
19 |
20 | ## V 1.0.6
21 | 1. Add screen casting parameters to set wake up and screen after screen casting
22 |
23 | ## V 1.0.5
24 | 1. Add more on-screen buttons for easy multi-control
25 | 2. IP After the connection, save the last connection IP address
26 |
27 |
28 | ## V 1.0.4
29 | 1. Add screen click shortcut, Alt+C
30 | 2. Add home button shortcut, Alt+H
31 |
32 |
33 | ## V 1.0.1
34 | Add keyboard input options and select On in scrpy Settings
--------------------------------------------------------------------------------
/Docs/Update.md:
--------------------------------------------------------------------------------
1 | # 更新日志
2 |
3 | ## V 1.1
4 | 1. 增加自动化任务
5 |
6 |
7 | ## V 1.0.8.1
8 | 1. 增加窗口置顶和投屏置顶
9 |
10 | ## V 1.0.8
11 | 1. 增加自定义快捷键功能(入口为 右上角设置图标)
12 | 2. 增加无线授权方式(不用通过usb授权)
13 | 3. 增加无线授权的API
14 |
15 | ## V 1.0.7
16 | 1. 添加英语支持
17 |
18 | ## V 1.0.6
19 | 1. 增加投屏参数 可设置保持唤醒和投屏后息屏
20 |
21 | ## V 1.0.5
22 | 1. 增加更多的屏幕按钮,方便多控
23 | 2. IP连接后,保存上一次的连接IP
24 |
25 |
26 | ## V 1.0.4
27 | 1. 加入屏幕点击接口,快捷键Alt+C
28 | 2. 加入home键快捷键 Alt+H
29 |
30 |
31 | ## V 1.0.1
32 | 增加键盘输入选项,在scrpy设置里选择开启
--------------------------------------------------------------------------------
/Docs/autohotkey.ahk:
--------------------------------------------------------------------------------
1 | ;设备名称 如果是ip地址可以不用填写端口号
2 | device :="192.168.191.3"
3 | ;api地址
4 | api_url :="http://192.168.8.242:12345"
5 |
6 | ;锁屏
7 | !1::
8 | {
9 |
10 | Run 'curl "' . api_url . '/api/Device/Lock?devicename=' . device . '"',,"hide"
11 | }
12 | ;音量-
13 | !Down::
14 | {
15 |
16 | Run 'curl "' . api_url . '/api/Device/SendKey?devicename=' . device . '&Key=KEYCODE_VOLUME_DOWN"',,"hide"
17 | }
18 | ;音量+
19 | !Up::
20 | {
21 |
22 | Run 'curl "' . api_url . '/api/Device/SendKey?devicename=' . device . '&Key=KEYCODE_VOLUME_UP"',,"hide"
23 | }
24 |
25 | ;多媒体 下一个
26 | !Right::
27 | {
28 |
29 | Run 'curl "' . api_url . '/api/Device/SendKey?devicename=' . device . '&Key=KEYCODE_MEDIA_NEXT"',,"hide"
30 | }
31 |
32 | ;多媒体 上一个
33 | !Left::
34 | {
35 |
36 | Run 'curl "' . api_url . '/api/Device/SendKey?devicename=' . device . '&KEYCODE_MEDIA_PLAY_PAUSE"',,"hide"
37 | }
38 | ;多媒体 暂停播放
39 | !Numpad5::
40 | {
41 |
42 | Run 'curl "' . api_url . '/api/Device/SendKey?devicename=' . device . '&Key=KEYCODE_MEDIA_PLAY"',,"hide"
43 | }
44 | ;上滑
45 | !q::
46 | {
47 |
48 | Run 'curl "' . api_url . '/api/Device/SendSwipe?devicename=' . device . '&direct=up"',,"hide"
49 | }
50 |
51 | ;下滑
52 | !w::
53 | {
54 |
55 | Run 'curl "' . api_url . '/api/Device/SendSwipe?devicename=' . device . '&direct=down"',,"hide"
56 | }
57 |
58 | ;桌面
59 | !2::
60 | {
61 |
62 | Run 'curl "' . api_url . '/api/Device/SendKey?devicename=' . device . '&Key=3"',,"hide"
63 | }
64 |
65 | ;检查设备连接情况
66 | CheckConnection() {
67 | ; 使用Run而不是RunWait,这样我们可以看到curl的输出
68 | OutputVar :=ExecScript('curl --connect-timeout 5 "' . api_url . '/api/Device/List"')
69 | ;MsgBox "Result: " OutputVar
70 |
71 | If not InStr(OutputVar, device){
72 | MsgBox "设备已经掉线"
73 | Pause
74 | }
75 |
76 | }
77 |
78 |
79 | ;测试
80 | !t::
81 | {
82 | CheckConnection()
83 |
84 | }
85 |
86 | ExecScript(Script, Wait:=true)
87 | {
88 | shell := ComObject("WScript.Shell")
89 | exec := shell.Exec(Script)
90 | ; exec.StdIn.Write(Script)
91 | exec.StdIn.Close()
92 | if Wait
93 | return exec.StdOut.ReadAll()
94 | }
95 | ;隐藏控制台
96 | DllCall("AllocConsole")
97 | WinHide "ahk_id " DllCall("GetConsoleWindow", "ptr")
98 | ; 设置定时器,每5分钟调用一次RunBatchFile函数
99 | ; 注意:时间是以毫秒为单位的,所以5分钟是5 * 60 * 1000 = 300000毫秒
100 | SetTimer CheckConnection, 5000 ; 5分钟定时器
--------------------------------------------------------------------------------
/Docs/task.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Name": "每5秒下滑",
4 | "TaskItems": [
5 | {
6 | "Oprate": "shell input swipe",
7 | "Param": "540 1300 540 500 1000",
8 | "IsAdb": true
9 | }
10 | ],
11 | "id": 1,
12 | "RunTimes": 1,
13 | "DeviceName": "419218f7",
14 | "Corn": "0/5 * * * * ?",
15 | "IsRun": true
16 | },
17 | {
18 | "Name": "打开钉钉进入工作台",
19 | "TaskItems": [
20 | {
21 | "Oprate": "shell am start -n",
22 | "Param": "com.alibaba.android.rimet/com.alibaba.android.rimet.biz.LaunchHomeActivity",
23 | "IsAdb": true
24 | },
25 | {
26 | "Oprate": "sleep",
27 | "Param": "5000",
28 | "IsAdb": false
29 | },
30 | {
31 | "Oprate": "shell input tap",
32 | "Param": "523 2326",
33 | "IsAdb": true
34 | }
35 | ],
36 | "id": 2,
37 | "RunTimes": 1,
38 | "DeviceName": "192.168.191.2:5555",
39 | "Corn": "",
40 | "IsRun": false
41 | }
42 | ]
--------------------------------------------------------------------------------
/HotKeyControl.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class HotKeyControl
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region 组件设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.EventName = new AntdUI.Label();
32 | this.Key = new AntdUI.Button();
33 | this.ModifyKey = new AntdUI.Dropdown();
34 | this.SuspendLayout();
35 | //
36 | // EventName
37 | //
38 | this.EventName.Location = new System.Drawing.Point(0, 9);
39 | this.EventName.Name = "EventName";
40 | this.EventName.Size = new System.Drawing.Size(102, 23);
41 | this.EventName.TabIndex = 0;
42 | this.EventName.Text = "label1";
43 | //
44 | // Key
45 | //
46 | this.Key.Location = new System.Drawing.Point(203, 4);
47 | this.Key.Name = "Key";
48 | this.Key.Size = new System.Drawing.Size(79, 35);
49 | this.Key.TabIndex = 2;
50 | this.Key.Text = "button2";
51 | this.Key.Click += new System.EventHandler(this.button2_Click);
52 | this.Key.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Key_KeyDown);
53 | //
54 | // ModifyKey
55 | //
56 | this.ModifyKey.Items.AddRange(new object[] {
57 | "Alt",
58 | "Ctrl",
59 | "Ctrl+Alt"});
60 | this.ModifyKey.Location = new System.Drawing.Point(108, 3);
61 | this.ModifyKey.Name = "ModifyKey";
62 | this.ModifyKey.Size = new System.Drawing.Size(89, 36);
63 | this.ModifyKey.TabIndex = 3;
64 | this.ModifyKey.Text = "dropdown1";
65 | this.ModifyKey.SelectedValueChanged += new AntdUI.ObjectNEventHandler(this.ModifyKey_SelectedValueChanged);
66 | //
67 | // HotKeyControl
68 | //
69 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
70 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
71 | this.Controls.Add(this.ModifyKey);
72 | this.Controls.Add(this.Key);
73 | this.Controls.Add(this.EventName);
74 | this.Name = "HotKeyControl";
75 | this.Size = new System.Drawing.Size(297, 44);
76 | this.Load += new System.EventHandler(this.HotKeyControl_Load);
77 | this.ResumeLayout(false);
78 |
79 | }
80 |
81 | #endregion
82 |
83 | private AntdUI.Label EventName;
84 | private AntdUI.Button Key;
85 | private AntdUI.Dropdown ModifyKey;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/HotKeyControl.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Model;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Data;
7 | using System.Drawing;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 |
13 | namespace MobileControlGuru
14 | {
15 | public partial class HotKeyControl : UserControl
16 | {
17 | //public string EventName { get; set; }
18 | //public string ModifyKey { get; set; }
19 | //public string Key { get; set; }
20 |
21 | public KeyItem KeyItem { get; set; }
22 | public HotKeyControl(KeyItem keyItem)
23 | {
24 | InitializeComponent();
25 | this.KeyItem = keyItem;
26 | }
27 |
28 |
29 | private void HotKeyControl_Load(object sender, EventArgs e)
30 | {
31 | //this.Tag = KeyItem;
32 | this.EventName.Text= KeyItem.EventName;
33 | if (ConfigHelp.GetConfig("lang") == "en")
34 | {
35 | this.EventName.Text = KeyItem.EventEngName;
36 | }
37 | this.ModifyKey.Text= KeyItem.ModifyKey;
38 | this.Key.Text= KeyItem.Key;
39 |
40 |
41 | }
42 |
43 | private void button2_Click(object sender, EventArgs e)
44 | {
45 |
46 | }
47 |
48 | private void ModifyKey_SelectedValueChanged(object sender, object value)
49 | {
50 | AntdUI.Dropdown s = (AntdUI.Dropdown)sender;
51 | s.Text = value.ToString();
52 | }
53 |
54 | private void Key_KeyDown(object sender, KeyEventArgs e)
55 | {
56 | var input = (AntdUI.Button)sender;
57 | //KeysConverter keysConverter = new KeysConverter();
58 | //input.Text = keysConverter.ConvertToString(e.KeyCode);
59 | string keyCode = e.KeyCode.ToString();
60 | if(keyCode== "ProcessKey")
61 | {
62 | return;
63 | }
64 | input.Text = e.KeyCode.ToString();
65 | }
66 |
67 | public KeyItem GetData()
68 | {
69 | this.KeyItem.ModifyKey = this.ModifyKey.Text;
70 | this.KeyItem.Key = this.Key.Text;
71 | return this.KeyItem;
72 | }
73 |
74 |
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/HotKeyControl.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/HotKeySetting.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class HotKeySetting
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HotKeySetting));
32 | this.button1 = new AntdUI.Button();
33 | this.flowLayoutPanel1 = new AntdUI.In.FlowLayoutPanel();
34 | this.label1 = new AntdUI.Label();
35 | this.SuspendLayout();
36 | //
37 | // button1
38 | //
39 | resources.ApplyResources(this.button1, "button1");
40 | this.button1.AutoEllipsis = true;
41 | this.button1.Name = "button1";
42 | this.button1.Click += new System.EventHandler(this.button1_Click);
43 | //
44 | // flowLayoutPanel1
45 | //
46 | resources.ApplyResources(this.flowLayoutPanel1, "flowLayoutPanel1");
47 | this.flowLayoutPanel1.Name = "flowLayoutPanel1";
48 | //
49 | // label1
50 | //
51 | resources.ApplyResources(this.label1, "label1");
52 | this.label1.Name = "label1";
53 | //
54 | // HotKeySetting
55 | //
56 | resources.ApplyResources(this, "$this");
57 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
58 | this.Controls.Add(this.label1);
59 | this.Controls.Add(this.flowLayoutPanel1);
60 | this.Controls.Add(this.button1);
61 | this.Name = "HotKeySetting";
62 | this.Load += new System.EventHandler(this.HotKeySetting_Load);
63 | this.ResumeLayout(false);
64 |
65 | }
66 |
67 | #endregion
68 | private AntdUI.Button button1;
69 | private AntdUI.In.FlowLayoutPanel flowLayoutPanel1;
70 | private AntdUI.Label label1;
71 | }
72 | }
--------------------------------------------------------------------------------
/HotKeySetting.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using MobileControlGuru.Model;
3 | using MobileControlGuru.Src;
4 | using MobileControlGuru.Tools;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.ComponentModel;
8 | using System.Data;
9 | using System.Drawing;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 | using System.Windows.Forms;
14 |
15 | namespace MobileControlGuru
16 | {
17 | public partial class HotKeySetting : BaseForm
18 | {
19 | public Src.MyHotKey myHotKey { set; get; }
20 | public HotKeySetting(Src.MyHotKey myHotKey)
21 | {
22 | InitializeComponent();
23 | resources = new ComponentResourceManager(typeof(HotKeySetting));
24 | this.myHotKey = myHotKey;
25 | }
26 |
27 | private void HotKeySetting_Load(object sender, EventArgs e)
28 | {
29 | foreach (var item in MyHotKey.GetKeyItems())
30 | {
31 |
32 | HotKeyControl htc = new HotKeyControl(item);
33 | this.flowLayoutPanel1.Controls.Add(htc);
34 | }
35 |
36 | }
37 | ///
38 | /// 初始化快捷键
39 | ///
40 | ///
41 |
42 | private void button1_Click(object sender, EventArgs e)
43 | {
44 |
45 |
46 | try
47 | {
48 | ConfigHelp.SetSetting("hotkeys", GetSetting());
49 | myHotKey.UnRegister();
50 | myHotKey.Register();
51 | MessageBox.Show(resources.GetString("SaveInfo"));
52 | }
53 | catch(Exception ex)
54 | {
55 | MessageBox.Show(ex.Message);
56 | }
57 |
58 | }
59 |
60 | private string GetSetting()
61 | {
62 | var keyssetting= new List();
63 | foreach(HotKeyControl control in this.flowLayoutPanel1.Controls)
64 | {
65 | keyssetting.Add(control.GetData());
66 | }
67 |
68 | return Newtonsoft.Json.JsonConvert.SerializeObject(keyssetting);
69 | }
70 |
71 | private void button2_Click(object sender, EventArgs e)
72 | {
73 |
74 | }
75 |
76 |
77 | private void button2_KeyDown(object sender, KeyEventArgs e)
78 | {
79 | var input = (AntdUI.Button)sender;
80 | //KeysConverter keysConverter = new KeysConverter();
81 | //input.Text = keysConverter.ConvertToString(e.KeyCode);
82 | input.Text = e.KeyCode.ToString();
83 | }
84 |
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/IPConnect.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class IPConnect
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IPConnect));
32 | this.ip_input = new AntdUI.Input();
33 | this.label1 = new AntdUI.Label();
34 | this.panel1 = new AntdUI.Panel();
35 | this.button1 = new AntdUI.Button();
36 | this.connect_btn = new AntdUI.Button();
37 | this.port_input = new AntdUI.InputNumber();
38 | this.label2 = new AntdUI.Label();
39 | this.panel1.SuspendLayout();
40 | this.SuspendLayout();
41 | //
42 | // ip_input
43 | //
44 | resources.ApplyResources(this.ip_input, "ip_input");
45 | this.ip_input.Name = "ip_input";
46 | //
47 | // label1
48 | //
49 | resources.ApplyResources(this.label1, "label1");
50 | this.label1.Name = "label1";
51 | //
52 | // panel1
53 | //
54 | resources.ApplyResources(this.panel1, "panel1");
55 | this.panel1.Controls.Add(this.button1);
56 | this.panel1.Controls.Add(this.connect_btn);
57 | this.panel1.Controls.Add(this.port_input);
58 | this.panel1.Controls.Add(this.label2);
59 | this.panel1.Controls.Add(this.label1);
60 | this.panel1.Controls.Add(this.ip_input);
61 | this.panel1.Name = "panel1";
62 | this.panel1.Click += new System.EventHandler(this.panel1_Click);
63 | //
64 | // button1
65 | //
66 | resources.ApplyResources(this.button1, "button1");
67 | this.button1.Name = "button1";
68 | this.button1.Type = AntdUI.TTypeMini.Success;
69 | this.button1.Click += new System.EventHandler(this.button1_Click);
70 | //
71 | // connect_btn
72 | //
73 | resources.ApplyResources(this.connect_btn, "connect_btn");
74 | this.connect_btn.Name = "connect_btn";
75 | this.connect_btn.Type = AntdUI.TTypeMini.Primary;
76 | this.connect_btn.Click += new System.EventHandler(this.connect_btn_Click);
77 | //
78 | // port_input
79 | //
80 | resources.ApplyResources(this.port_input, "port_input");
81 | this.port_input.Maximum = new decimal(new int[] {
82 | 999999,
83 | 0,
84 | 0,
85 | 0});
86 | this.port_input.Name = "port_input";
87 | //
88 | // label2
89 | //
90 | resources.ApplyResources(this.label2, "label2");
91 | this.label2.Name = "label2";
92 | //
93 | // IPConnect
94 | //
95 | resources.ApplyResources(this, "$this");
96 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
97 | this.Controls.Add(this.panel1);
98 | this.Name = "IPConnect";
99 | this.Load += new System.EventHandler(this.IPConnect_Load);
100 | this.panel1.ResumeLayout(false);
101 | this.ResumeLayout(false);
102 |
103 | }
104 |
105 | #endregion
106 |
107 | private AntdUI.Input ip_input;
108 | private AntdUI.Label label1;
109 | private AntdUI.Panel panel1;
110 | private AntdUI.Label label2;
111 | private AntdUI.Button connect_btn;
112 | private AntdUI.InputNumber port_input;
113 | private AntdUI.Button button1;
114 | }
115 | }
--------------------------------------------------------------------------------
/IPConnect.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using MobileControlGuru.Base;
3 | using MobileControlGuru.Src;
4 | using MobileControlGuru.Tools;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.ComponentModel;
8 | using System.Data;
9 | using System.Drawing;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 | using System.Windows.Forms;
15 |
16 | namespace MobileControlGuru
17 | {
18 | public partial class IPConnect : BaseForm
19 | {
20 |
21 | public MobileControlGuru.MainForm main { set; get; }
22 | public IPConnect(MobileControlGuru.MainForm _main)
23 | {
24 | this.main = _main;
25 | InitializeComponent();
26 | resources = new ComponentResourceManager(typeof(IPConnect));
27 | }
28 |
29 |
30 |
31 | private void connect_btn_Click(object sender, EventArgs e)
32 | {
33 | string device_ip = this.ip_input.Text;
34 | string port = this.port_input.Text;
35 | var adbinfo = ADB.Connect($"{device_ip}:{port}");
36 | DeviceManager.Instance.UpdateDevices();
37 | Properties.Settings.Default.LastDeviceIP = device_ip;
38 | Properties.Settings.Default.Save();
39 | this.Close();
40 | }
41 |
42 |
43 |
44 | private void IPConnect_Load(object sender, EventArgs e)
45 | {
46 | this.ip_input.Text = Properties.Settings.Default.LastDeviceIP;
47 |
48 |
49 | }
50 | private void button1_Click(object sender, EventArgs e)
51 | {
52 | string device_ip = this.ip_input.Text;
53 | string port = this.port_input.Text;
54 |
55 | var p = Scrcpy.IPConnet(device_ip, port);
56 | if (p == null)
57 | {
58 | MessageBox.Show(resources.GetString("connetError"));
59 | return;
60 | }
61 | DeviceManager.Instance.BindDevicesProcees(device_ip + ":" + port, p);
62 | Properties.Settings.Default.LastDeviceIP = device_ip;
63 | Properties.Settings.Default.Save();
64 |
65 | this.Close();
66 |
67 | }
68 |
69 | private void panel1_Click(object sender, EventArgs e)
70 | {
71 | var lang = Tools.ConfigHelp.GetConfig("Lang");
72 | if (!string.IsNullOrEmpty(lang))
73 | {
74 | ChangeLang(lang);
75 | ApplyResource();
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/IPPair.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class IPPair
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IPPair));
32 | this.button1 = new AntdUI.Button();
33 | this.port_input = new AntdUI.InputNumber();
34 | this.label2 = new AntdUI.Label();
35 | this.label1 = new AntdUI.Label();
36 | this.ip_input = new AntdUI.Input();
37 | this.code_input = new AntdUI.InputNumber();
38 | this.label3 = new AntdUI.Label();
39 | this.SuspendLayout();
40 | //
41 | // button1
42 | //
43 | resources.ApplyResources(this.button1, "button1");
44 | this.button1.Name = "button1";
45 | this.button1.Type = AntdUI.TTypeMini.Success;
46 | this.button1.Click += new System.EventHandler(this.connect_btn_Click);
47 | //
48 | // port_input
49 | //
50 | resources.ApplyResources(this.port_input, "port_input");
51 | this.port_input.Name = "port_input";
52 | //
53 | // label2
54 | //
55 | resources.ApplyResources(this.label2, "label2");
56 | this.label2.Name = "label2";
57 | //
58 | // label1
59 | //
60 | resources.ApplyResources(this.label1, "label1");
61 | this.label1.Name = "label1";
62 | //
63 | // ip_input
64 | //
65 | resources.ApplyResources(this.ip_input, "ip_input");
66 | this.ip_input.Name = "ip_input";
67 | //
68 | // code_input
69 | //
70 | resources.ApplyResources(this.code_input, "code_input");
71 | this.code_input.Name = "code_input";
72 | //
73 | // label3
74 | //
75 | resources.ApplyResources(this.label3, "label3");
76 | this.label3.Name = "label3";
77 | //
78 | // IPPair
79 | //
80 | resources.ApplyResources(this, "$this");
81 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
82 | this.Controls.Add(this.code_input);
83 | this.Controls.Add(this.label3);
84 | this.Controls.Add(this.button1);
85 | this.Controls.Add(this.port_input);
86 | this.Controls.Add(this.label2);
87 | this.Controls.Add(this.label1);
88 | this.Controls.Add(this.ip_input);
89 | this.Name = "IPPair";
90 | this.ResumeLayout(false);
91 |
92 | }
93 |
94 | #endregion
95 |
96 | private AntdUI.Button button1;
97 | private AntdUI.InputNumber port_input;
98 | private AntdUI.Label label2;
99 | private AntdUI.Label label1;
100 | private AntdUI.Input ip_input;
101 | private AntdUI.InputNumber code_input;
102 | private AntdUI.Label label3;
103 | }
104 | }
--------------------------------------------------------------------------------
/IPPair.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Base;
2 | using MobileControlGuru.Properties;
3 | using MobileControlGuru.Src;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.ComponentModel;
7 | using System.Data;
8 | using System.Drawing;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Windows.Forms;
13 |
14 | namespace MobileControlGuru
15 | {
16 | public partial class IPPair : BaseForm
17 | {
18 | public MobileControlGuru.MainForm main { set; get; }
19 | public IPPair(MobileControlGuru.MainForm _main)
20 | {
21 | this.main = _main;
22 | InitializeComponent();
23 | resources = new ComponentResourceManager(typeof(IPConnect));
24 | }
25 |
26 |
27 |
28 | private void connect_btn_Click(object sender, EventArgs e)
29 | {
30 | string device_ip = this.ip_input.Text;
31 | int port = Convert.ToInt32(this.port_input.Text);
32 | int code =Convert.ToInt32( this.code_input.Text);
33 | var adbinfo = ADB.Pair(device_ip,port, code);
34 | DeviceManager.Instance.UpdateDevices();
35 | Properties.Settings.Default.LastDeviceIP = device_ip;
36 | Properties.Settings.Default.Save();
37 | this.Close();
38 | }
39 |
40 |
41 |
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/MobileControlGuru.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.9.34622.214
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileControlGuru", "MobileControlGuru.csproj", "{1608A03F-C735-44A7-9BD8-A4C654C03B70}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {1608A03F-C735-44A7-9BD8-A4C654C03B70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {1608A03F-C735-44A7-9BD8-A4C654C03B70}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {1608A03F-C735-44A7-9BD8-A4C654C03B70}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {1608A03F-C735-44A7-9BD8-A4C654C03B70}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {14A00F26-7AC4-4F6B-B4D0-41546EBE0CA0}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/MoblieControl.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace MobileControlGuru
2 | {
3 | partial class MoblieControl
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region 组件设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MoblieControl));
32 | this.input1 = new AntdUI.Input();
33 | this.put = new AntdUI.Button();
34 | this.wireless_connect = new AntdUI.Button();
35 | this.flowLayoutPanel1 = new AntdUI.In.FlowLayoutPanel();
36 | this.checkbox1 = new AntdUI.Checkbox();
37 | this.disput = new AntdUI.Button();
38 | this.disconnect = new AntdUI.Button();
39 | this.show = new AntdUI.Button();
40 | this.ontop = new AntdUI.Button();
41 | this.flowLayoutPanel1.SuspendLayout();
42 | this.SuspendLayout();
43 | //
44 | // input1
45 | //
46 | resources.ApplyResources(this.input1, "input1");
47 | this.input1.Name = "input1";
48 | this.input1.ReadOnly = true;
49 | //
50 | // put
51 | //
52 | resources.ApplyResources(this.put, "put");
53 | this.put.Name = "put";
54 | this.put.Type = AntdUI.TTypeMini.Success;
55 | this.put.Click += new System.EventHandler(this.put_Click);
56 | //
57 | // wireless_connect
58 | //
59 | resources.ApplyResources(this.wireless_connect, "wireless_connect");
60 | this.wireless_connect.Name = "wireless_connect";
61 | this.wireless_connect.Click += new System.EventHandler(this.wireless_connect_Click);
62 | //
63 | // flowLayoutPanel1
64 | //
65 | this.flowLayoutPanel1.Controls.Add(this.checkbox1);
66 | this.flowLayoutPanel1.Controls.Add(this.input1);
67 | this.flowLayoutPanel1.Controls.Add(this.put);
68 | this.flowLayoutPanel1.Controls.Add(this.disput);
69 | this.flowLayoutPanel1.Controls.Add(this.wireless_connect);
70 | this.flowLayoutPanel1.Controls.Add(this.disconnect);
71 | this.flowLayoutPanel1.Controls.Add(this.show);
72 | this.flowLayoutPanel1.Controls.Add(this.ontop);
73 | resources.ApplyResources(this.flowLayoutPanel1, "flowLayoutPanel1");
74 | this.flowLayoutPanel1.Name = "flowLayoutPanel1";
75 | //
76 | // checkbox1
77 | //
78 | resources.ApplyResources(this.checkbox1, "checkbox1");
79 | this.checkbox1.Name = "checkbox1";
80 | this.checkbox1.CheckedChanged += new AntdUI.BoolEventHandler(this.checkbox1_CheckedChanged);
81 | //
82 | // disput
83 | //
84 | resources.ApplyResources(this.disput, "disput");
85 | this.disput.Name = "disput";
86 | this.disput.Type = AntdUI.TTypeMini.Warn;
87 | this.disput.Click += new System.EventHandler(this.disput_Click);
88 | //
89 | // disconnect
90 | //
91 | resources.ApplyResources(this.disconnect, "disconnect");
92 | this.disconnect.Name = "disconnect";
93 | this.disconnect.Type = AntdUI.TTypeMini.Error;
94 | this.disconnect.Click += new System.EventHandler(this.disconnect_Click);
95 | //
96 | // show
97 | //
98 | this.show.BackgroundImage = global::MobileControlGuru.Properties.Resources.see;
99 | this.show.Ghost = true;
100 | this.show.ImageSvg = "";
101 | resources.ApplyResources(this.show, "show");
102 | this.show.Name = "show";
103 | this.show.Click += new System.EventHandler(this.show_Click);
104 | //
105 | // ontop
106 | //
107 | this.ontop.BackgroundImage = global::MobileControlGuru.Properties.Resources.to_top;
108 | this.ontop.Ghost = true;
109 | this.ontop.ImageSvg = "";
110 | resources.ApplyResources(this.ontop, "ontop");
111 | this.ontop.Name = "ontop";
112 | this.ontop.Click += new System.EventHandler(this.ontop_Click);
113 | //
114 | // MoblieControl
115 | //
116 | resources.ApplyResources(this, "$this");
117 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
118 | this.Controls.Add(this.flowLayoutPanel1);
119 | this.Name = "MoblieControl";
120 | this.Load += new System.EventHandler(this.MoblieControl_Load);
121 | this.flowLayoutPanel1.ResumeLayout(false);
122 | this.ResumeLayout(false);
123 |
124 | }
125 |
126 | #endregion
127 |
128 | private AntdUI.Input input1;
129 | private AntdUI.Button put;
130 | private AntdUI.Button wireless_connect;
131 | private AntdUI.In.FlowLayoutPanel flowLayoutPanel1;
132 | private AntdUI.Button disconnect;
133 | private AntdUI.Button disput;
134 | private AntdUI.Checkbox checkbox1;
135 | private AntdUI.Button ontop;
136 | private AntdUI.Button show;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/MoblieControl.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using Microsoft.VisualBasic;
3 | using MobileControlGuru.Base;
4 | using MobileControlGuru.Model;
5 | using MobileControlGuru.Properties;
6 | using MobileControlGuru.Src;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.ComponentModel;
10 | using System.Data;
11 | using System.Diagnostics;
12 | using System.Drawing;
13 | using System.Linq;
14 | using System.Text;
15 | using System.Text.RegularExpressions;
16 | using System.Threading;
17 | using System.Threading.Tasks;
18 | using System.Windows.Forms;
19 | using static Microsoft.WindowsAPICodePack.Shell.PropertySystem.SystemProperties.System;
20 |
21 | namespace MobileControlGuru
22 | {
23 | public partial class MoblieControl : BaseControl
24 | {
25 |
26 | public Model.Device device { set; get; }
27 | public MoblieControl()
28 | {
29 | InitializeComponent();
30 | }
31 | public MoblieControl(Model.Device device)
32 | {
33 | resources = new ComponentResourceManager(typeof(MoblieControl));
34 | InitializeComponent();
35 |
36 | this.device = device;
37 |
38 | }
39 | private void MoblieControl_Load(object sender, EventArgs e)
40 | {
41 | this.input1.Text = device.Name;
42 |
43 | this.checkbox1.Checked=device.Selected;
44 | this.wireless_connect.Visible = !this.device.IsTcpIP;
45 | this.disconnect.Visible = this.device.IsTcpIP;
46 | this.ontop.BackgroundImage = this.device.IsTop ? Resources.ontop : Resources.ontop_blur;
47 | this.disput.Visible= this.device.ScrcpyProcess!=null;
48 | this.put.Visible = this.device.ScrcpyProcess == null;
49 |
50 | if (device.form != null)
51 | {
52 | this.show.Visible = true;
53 | this.show.BackgroundImage = device.form.Visible? Resources.see: Resources.nosee;
54 | }
55 | else
56 | {
57 | this.show.Visible = false;
58 | }
59 |
60 | }
61 |
62 | private void put_Click(object sender, EventArgs e)
63 | {
64 | Process process = Scrcpy.Put(this.device.Name);
65 | //while (process.MainWindowHandle == IntPtr.Zero)
66 | //{
67 | // Thread.Sleep(100);
68 | //}
69 | //device.form=new ScrcpyForm(device.Name,process);
70 | //device.ScrcpyProcess= process;
71 | //device.form.Show();
72 | //device.form.FormClosed += ScrcpyClosed;
73 | DeviceManager.Instance.BindDevicesProcees(this.device.Name, process);
74 | DeviceManager.Instance.UpdateDevices();
75 | }
76 |
77 | private void ScrcpyClosed(object sender, FormClosedEventArgs e)
78 | {
79 | //device.ScrcpyProcess.Kill();
80 | device.ScrcpyProcess = null;
81 | DeviceManager.Instance.UpdateDevices();
82 | }
83 |
84 | private void checkbox1_CheckedChanged(object sender, bool value)
85 | {
86 | device.Selected = value;
87 |
88 | }
89 |
90 | private void wireless_connect_Click(object sender, EventArgs e)
91 | {
92 |
93 | string str = Interaction.InputBox("提示信息", "请输入手机IP", "", -1, -1);
94 | if (string.IsNullOrEmpty(str))
95 | {
96 | return;
97 | }
98 | ADB.Exec($"-s {this.device.Name} tcpip 5555");
99 | Thread.Sleep(1000);
100 | ADB.Connect(str);
101 | }
102 |
103 | private void disconnect_Click(object sender, EventArgs e)
104 | {
105 | DialogResult AF = MessageBox.Show("确定断开连接吗?", "确认框", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
106 | if (AF == DialogResult.OK)
107 | {
108 | ADB.Exec("disconnect " + this.device.Name);
109 | DeviceManager.Instance.UpdateDevices();
110 | }
111 | }
112 |
113 | private void disput_Click(object sender, EventArgs e)
114 | {
115 |
116 | DialogResult AF = MessageBox.Show("确定关闭投屏", "确认框", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
117 | if (AF == DialogResult.OK)
118 | {
119 |
120 | device.ScrcpyProcess.Kill();
121 | device.ScrcpyProcess = null;
122 | device.form?.Dispose();
123 | device.form = null;
124 | DeviceManager.Instance.UpdateDevices();
125 | }
126 | }
127 |
128 | private void ontop_Click(object sender, EventArgs e)
129 | {
130 | this.device.IsTop = !this.device.IsTop;
131 | ((AntdUI.Button)sender).BackgroundImage = this.device.IsTop ? Resources.to_top : Resources.to_top_blur;
132 | DeviceManager.Instance.UpdateDevices();
133 | }
134 |
135 | private void show_Click(object sender, EventArgs e)
136 | {
137 | if(this.device.form==null) {
138 | return;
139 | }
140 | var btn = (AntdUI.Button)sender;
141 | if (this.device.form.Visible)
142 | {
143 | this.device.form.Hide();
144 | }
145 | else
146 | {
147 | this.device.form.Show();
148 | }
149 | btn.BackgroundImage = device.form.Visible ? Resources.see : Resources.nosee;
150 |
151 | }
152 |
153 | private void button2_Click(object sender, EventArgs e)
154 | {
155 |
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Model/Device.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using MobileControlGuru.AutoTask;
3 | using MobileControlGuru.Src;
4 | using MobileControlGuru.Tools;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Diagnostics;
8 | using System.Drawing;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Windows.Forms;
13 | using static AntdUI.Modal;
14 | using static System.Windows.Forms.VisualStyles.VisualStyleElement;
15 |
16 | namespace MobileControlGuru.Model
17 | {
18 | ///
19 | /// 设备模型类
20 | ///
21 | public class Device
22 | {
23 | public string Name { get; set; }
24 |
25 | public string ScrcpyParams { get; set; }
26 | public bool Selected { get; set; }
27 | public string Status { set; get; }
28 |
29 | //public IntPtr hook { set; get; }
30 | public ScrcpyMonitor monitor { set; get; }
31 | public bool IsTcpIP { get; set; }
32 | public bool IsTop { get; set; }
33 |
34 | public ScrcpyForm form { set; get; }
35 | public Process ScrcpyProcess { get; set; }
36 | public TaskRunWindow RunWindow { get; set; }
37 |
38 | }
39 |
40 |
41 |
42 | public enum PutType
43 | {
44 | None = 0,
45 | Puted = 1,
46 |
47 | }
48 | ///
49 | /// table 的模型类
50 | ///
51 | public class DeviceItem : Device
52 | {
53 | public bool IsSelected { get; set; }
54 |
55 | public bool IsTcpIP { get; set; }
56 | public PutType PutType { get; set; }
57 | public AntdUI.ICell[] btns { get; set; }
58 | public AntdUI.ICell status { get; set; }
59 |
60 |
61 | public DeviceItem(Device device)
62 | {
63 | this.Name = device.Name;
64 | this.PutType = PutType.None;
65 | this.IsTcpIP = Tools.Common.IsValidIP(device.Name);
66 | var btns = new List();
67 | if(device.Status== "device")
68 | {
69 |
70 | if (!IsTcpIP)
71 | {
72 | btns.Add(new AntdUI.CellButton("usb_put", "有线投屏", AntdUI.TTypeMini.Success));
73 |
74 | }
75 | else
76 | {
77 | btns.Add(new AntdUI.CellButton("ip_put", "无线投屏", AntdUI.TTypeMini.Success));
78 |
79 | }
80 | if (device.ScrcpyProcess != null)
81 | {
82 | this.PutType = PutType.Puted;
83 | btns.Add(new AntdUI.CellButton("close_put", "停止投屏", AntdUI.TTypeMini.Error));
84 | }
85 | //btns.Add(new AntdUI.CellButton("put_params", "投屏参数", AntdUI.TTypeMini.Primary));
86 | status = new AntdUI.CellText("在线", Color.Green);
87 |
88 |
89 | }
90 | else
91 | {
92 | status=new AntdUI.CellText("离线", Color.Gray);
93 | }
94 |
95 | btns.Add(new AntdUI.CellButton("disconnected", "断开连接", AntdUI.TTypeMini.Error));
96 |
97 | this.btns = btns.ToArray();
98 | }
99 |
100 |
101 | }
102 |
103 |
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/Model/KeyItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MobileControlGuru.Model
8 | {
9 | public class KeyItem
10 | {
11 | public string EventName { set; get; }
12 | public string EventEngName { set; get; }
13 | public int EventID { set; get; }
14 | public string ModifyKey { set; get; }
15 | public string Key { set; get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Preview/api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/api.png
--------------------------------------------------------------------------------
/Preview/hotkeysetting.en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/hotkeysetting.en.png
--------------------------------------------------------------------------------
/Preview/hotkeysetting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/hotkeysetting.png
--------------------------------------------------------------------------------
/Preview/ipconnect.en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/ipconnect.en.png
--------------------------------------------------------------------------------
/Preview/ipconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/ipconnect.png
--------------------------------------------------------------------------------
/Preview/main.en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/main.en.png
--------------------------------------------------------------------------------
/Preview/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/main.png
--------------------------------------------------------------------------------
/Preview/taskedit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/taskedit.png
--------------------------------------------------------------------------------
/Preview/taskmain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Preview/taskmain.png
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Principal;
5 | using System.Threading.Tasks;
6 | using System.Windows.Forms;
7 |
8 | namespace MobileControlGuru
9 | {
10 | internal static class Program
11 | {
12 | ///
13 | /// 应用程序的主入口点。
14 | ///
15 | [STAThread]
16 | static void Main()
17 | {
18 | Application.EnableVisualStyles();
19 | Application.SetCompatibleTextRenderingDefault(false);
20 | Application.Run(new MainForm());
21 | //Application.Run(new AutoTask.TaskList());
22 | }
23 | //private static bool IsRunningAsAdministrator()
24 | //{
25 | // WindowsIdentity identity = WindowsIdentity.GetCurrent();
26 | // WindowsPrincipal principal = new WindowsPrincipal(identity);
27 | // return principal.IsInRole(WindowsBuiltInRole.Administrator);
28 | //}
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("MobileControlGuru")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("MobileControlGuru")]
13 | [assembly: AssemblyCopyright("Copyright © 2024")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("1608a03f-c735-44a7-9bd8-a4c654c03b70")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.1.8.0")]
36 | [assembly: AssemblyFileVersion("1.1.8.0")]
37 |
--------------------------------------------------------------------------------
/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace MobileControlGuru.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("0, 0")]
29 | public global::System.Drawing.Point ClickPoint {
30 | get {
31 | return ((global::System.Drawing.Point)(this["ClickPoint"]));
32 | }
33 | set {
34 | this["ClickPoint"] = value;
35 | }
36 | }
37 |
38 | [global::System.Configuration.UserScopedSettingAttribute()]
39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
40 | [global::System.Configuration.DefaultSettingValueAttribute("")]
41 | public string LastDeviceIP {
42 | get {
43 | return ((string)(this["LastDeviceIP"]));
44 | }
45 | set {
46 | this["LastDeviceIP"] = value;
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 0, 0
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | # MobileControlGuru (Support HotKey, WebAPI Control,Multi-device)
2 |
3 | 简体中文 | English
4 |
5 | Update Log
6 |
7 | ## Feature
8 |
9 | 1. Multi-device control
10 | 2. Bulk operations
11 | 3. Support HotKey
12 | 4. API Control
13 |
14 | ## Instructions for use
15 |
16 | 1. run MobileControlGuru.exe
17 | 2. Enable the debugging mode of the phone and authorize the debugging
18 | 3. Click to get the list of devices
19 | 4. Click to get the device list, the device information appears in the left list, and you can start to control the phone (no screen projection required).
20 |
21 |
22 | ## Matters needing attention
23 |
24 | Close directly will not exit this program, please click the icon in the lower right corner to exit this program
25 |
26 | ### HotKey
27 |
28 | By default, only the first device is operated
29 |
30 | | HotKey | Action|
31 | | --- | --- |
32 | | Alt+D| Lock|
33 | | Alt+H| Home|
34 | | Alt+C| Tap screen|
35 | | Alt+↑| Volume plus |
36 | | Alt+↓| Volume down |
37 | | Alt+←| MediaPrevious|
38 | | Alt+→| MediaNext|
39 | | Alt+NumPad55| MediaPlayPause|
40 | | Alt+NumPad2| Swipe up(TikTok videos next)|
41 | | Alt+NumPad8| Swipe down(TikTok videos up)|
42 |
43 | ### API Description
44 |
45 | This feature is used to control non-native devices and should be enabled with caution.
46 |
47 | After enabling this feature, local network devices can invoke control commands for the local machine through API requests.
48 |
49 | This feature match[Curl](https://curl.se/download.html)and [AutoHotkey](https://[AutoHotkey](https://www.autohotkey.com/)), When multiple devices can let their respective computers operate their own phones
50 | Example AutoHotkey script Look at autohotkey.ahk in the docs directory
51 |
52 | #### API List
53 |
54 | By default, the WebPort is enabled on port 12345. You need to enter the config file to modify Webport properties
55 |
56 | |Url | Description|
57 | | --- | --- |
58 | | /api/Device/Connect| Connecting devices by IP (Step 1) |
59 | | /api/Device/List | List of current devices |
60 | | /api/Device/Lock |Send the lock screen command |
61 | | /api/Device/SendKey| Send keyCode value Please search for the key (adb keycode) |
62 | | /api/Device/SendSwipe | Send Swipe |
63 |
64 | ## Preview
65 |
66 | Main
67 |
68 | 
69 |
70 | IP Connect
71 |
72 | 
73 |
74 |
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 电脑多控手机(MobileControlGuru) 支持快捷键,WebAPI控制,自动化任务
2 |
3 |
4 |
5 |
6 |
7 | [更新日志](Docs/Update.md)
8 |
9 | ## 功能
10 |
11 | 1. 手机多控
12 | 2. 批量操作
13 | 3. 快捷键操作
14 | 4. API发布
15 | 5. 自动化任务
16 |
17 | ## 使用说明
18 |
19 | 1. 打开MobileControlGuru.exe
20 | 2. 手机开启调试模式并授权调试
21 | 3. 点击获取设备列表
22 | 4. 左边列表出现设备信息,即可开始控制手机(无需投屏)
23 |
24 |
25 |
26 |
27 | ### 快捷键说明
28 |
29 | 快捷键默认只操作第一个设备
30 |
31 | | 快捷键 | 操作|
32 | | --- | --- |
33 | | Alt+D| 锁屏|
34 | | Alt+H| Home键|
35 | | Alt+C| 点击屏幕(主界面按钮点击后生效)|
36 | | Alt+↑| 音量加 |
37 | | Alt+↓| 音量减 |
38 | | Alt+←| 媒体键 上一个|
39 | | Alt+→| 媒体键 下一个|
40 | | Alt+5(小键盘)| 媒体键 播放暂停|
41 | | Alt+2(小键盘)| 上滑(对应短视频下一个)|
42 | | Alt+8(小键盘)| 下滑(对应短视频上一个)|
43 |
44 | ## 自动化
45 | 详情见[自动化文档](Docs/Task.md)
46 |
47 |
48 |
49 |
50 | ### API说明
51 |
52 | 此功能用于非本机控制设备,需要谨慎开启。
53 |
54 | 开始后局域网设备可以通过API形式调用本机的控制指令
55 |
56 | 此功能搭配[Curl](https://curl.se/download.html)与[AutoHotkey](https://[AutoHotkey](https://www.autohotkey.com/))配合使用,当多设备时可以让各自的电脑操作自己的手机
57 | AutoHotkey脚本示例查看docs目录下的autohotkey.ahk
58 |
59 | #### API 列表
60 |
61 | 默认在12345端口打开,需要请自行进入config文件修改WebPort属性
62 |
63 | |地址 | 说明|
64 | | --- | --- |
65 | | /api/Device/Connect| 通过IP连接设备(第一步) |
66 | | /api/Device/List | 当前的设备列表 |
67 | | /api/Device/Lock | 发送锁屏指令 |
68 | | /api/Device/SendKey| 发送按键 keyCode数值请自行搜索关键(adb keycode) |
69 | | /api/Device/SendSwipe | 发送滑动指令 |
70 |
71 | ## 界面预览
72 |
73 | 主界面
74 |
75 | 
76 |
77 | IP连接
78 |
79 | 
80 |
81 | API
82 |
83 | 
84 |
85 |
86 |
87 | ## 注意事项
88 |
89 | 直接关闭不会退出本程序,请右击右下角图标退出本程序
--------------------------------------------------------------------------------
/Resources/fanhui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/fanhui.png
--------------------------------------------------------------------------------
/Resources/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/favicon.ico
--------------------------------------------------------------------------------
/Resources/jietu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/jietu.png
--------------------------------------------------------------------------------
/Resources/nosee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/nosee.png
--------------------------------------------------------------------------------
/Resources/ontop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/ontop.png
--------------------------------------------------------------------------------
/Resources/ontop_blur.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/ontop_blur.png
--------------------------------------------------------------------------------
/Resources/scrcpy-win64-v2.4.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/scrcpy-win64-v2.4.zip
--------------------------------------------------------------------------------
/Resources/scrcpy_params.json:
--------------------------------------------------------------------------------
1 | {
2 | "Params": [
3 | {
4 | //中文名
5 | "Name": "无音频",
6 | //英文名
7 | "EngName": "no-audio",
8 | //数据类型 0表示无值 1表示带值
9 | "Type": 0,
10 | "Val": "",
11 | //带值的限定范围
12 | "AllowValues": [
13 | ],
14 | //默认值
15 | "DefaultValues": "",
16 | //分组 同一分组的不能一起设置
17 | "Group": "",
18 | //scrcpy 参数
19 | "Param": "--no-audio",
20 | //scrcpy 短参数
21 | "ShortVersion": "",
22 | //是否允许可以设置
23 | "AllowSetting": true
24 | },
25 |
26 | {
27 |
28 | "Name": "键盘支持",
29 | "EngName": "keyboard",
30 | "Type": 0,
31 | "Val": "",
32 | "AllowValues": [
33 | {
34 | "Name": "sdk ",
35 | "EngName": "sdk",
36 | "Val": "sdk "
37 | },
38 | {
39 | "Name": "uhid",
40 | "EngName": "uhid",
41 | "Val": "uhid "
42 | },
43 | {
44 | "Name": "aoa",
45 | "EngName": "aoa",
46 | "Val": "aoa "
47 | },
48 | {
49 | "Name": "禁用",
50 | "EngName": "disabled",
51 | "Val": "disabled "
52 | }
53 | ],
54 | "DefaultValues": "sdk",
55 | "Group": "",
56 | "Param": "--keyboard",
57 | "ShortVersion": "",
58 | "AllowSetting": true
59 | },
60 | {
61 | "Name": "初始X轴",
62 | "EngName": "window-x",
63 | "Type": 1,
64 | "Param": "--window-x",
65 | "ShortVersion": "",
66 | "Group": "",
67 | "Val": "",
68 |
69 | "AllowSetting": true,
70 | "AllowValues": [
71 |
72 | ],
73 | "DefaultValues": ""
74 |
75 | },
76 | {
77 | "Name": "初始Y轴",
78 | "EngName": "window-y",
79 | "Type": 1,
80 | "Param": "--window-y",
81 | "ShortVersion": "",
82 | "DefaultValues": "",
83 | "Group": "",
84 | "AllowSetting": true,
85 | "Val": "",
86 | "AllowValues": [
87 |
88 | ]
89 |
90 | },
91 | {
92 | "Name": "默认宽度",
93 | "EngName": "window-width",
94 | "Type": 1,
95 | "Param": "--window-width",
96 | "Group": "",
97 | "DefaultValues": "",
98 | "AllowSetting": true,
99 | "ShortVersion": "",
100 | "AllowValues": [
101 |
102 | ],
103 | "Val": ""
104 | },
105 | {
106 | "Name": "默认高度",
107 | "EngName": "window-height",
108 | "Type": 1,
109 | "Param": "--window-height",
110 | "Group": "",
111 | "DefaultValues": "",
112 | "AllowSetting": true,
113 | "ShortVersion": "",
114 | "AllowValues": [
115 |
116 | ],
117 | "Val": ""
118 | }
119 | ],
120 | //运行时命令
121 | "RunningParams": [
122 |
123 |
124 | ]
125 | }
126 |
--------------------------------------------------------------------------------
/Resources/see.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/see.bmp
--------------------------------------------------------------------------------
/Resources/see.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/see.png
--------------------------------------------------------------------------------
/Resources/shouye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/shouye.png
--------------------------------------------------------------------------------
/Resources/to_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/to_top.png
--------------------------------------------------------------------------------
/Resources/to_top_blur.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yclown/MobileControlGuru/e6d3ad77a6ef7ced07351f5bc3821152390ffc19/Resources/to_top_blur.png
--------------------------------------------------------------------------------
/ScrcpyConrtrolPanel.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using MobileControlGuru.Base;
3 | using MobileControlGuru.Model;
4 | using MobileControlGuru.Src;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.ComponentModel;
8 | using System.Data;
9 | using System.Diagnostics;
10 | using System.Drawing;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 | using System.Windows.Forms;
15 |
16 | namespace MobileControlGuru
17 | {
18 | public partial class ScrcpyConrtrolPanel : Window
19 | {
20 |
21 | public Device Device { get; set; }
22 | public ScrcpyConrtrolPanel()
23 | {
24 | InitializeComponent();
25 | //this.BackColor = Color.Transparent;
26 | // 设置窗体的背景色为 LimeGreen,并将其设为透明色
27 | //this.BackColor = Color.LimeGreen;
28 | //this.TransparencyKey = Color.LimeGreen;
29 | //this.FormBorderStyle = FormBorderStyle.None;
30 | }
31 |
32 |
33 | private void screencap_btn_Click(object sender, EventArgs e)
34 | {
35 |
36 | new DeviceADB(Device.Name).ScreenCap();
37 | }
38 |
39 | private void home_btn_Click(object sender, EventArgs e)
40 | {
41 | new DeviceADB(Device.Name).SendHome();
42 | }
43 |
44 | private void back_btn_Click(object sender, EventArgs e)
45 | {
46 | ADB.SendKeyEvent(Device.Name, ADBKey.Key.KEYCODE_BACK);
47 |
48 | }
49 |
50 | private void exit_btn_Click(object sender, EventArgs e)
51 | {
52 |
53 |
54 | DialogResult AF = MessageBox.Show("确定关闭投屏吗?", "确认框", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
55 | if (AF == DialogResult.OK)
56 | {
57 | DeviceManager.Instance.Close(Device);
58 | DeviceManager.Instance.UpdateDevices();
59 | this.Hide();
60 | }
61 | else
62 | {
63 | //用户点击取消或者关闭对话框后执行的代码
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ScrcpyForm.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using MobileControlGuru.Base;
3 | using MobileControlGuru.Src;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.ComponentModel;
7 | using System.Data;
8 | using System.Diagnostics;
9 | using System.Drawing;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 | using System.Windows.Forms;
14 |
15 | namespace MobileControlGuru
16 | {
17 | public partial class ScrcpyForm : BaseForm
18 | {
19 | public Process ScrcpyProcess { get; set; }
20 | IntPtr childHwnd ;
21 | public string DeviceName { set; get; }
22 | public ScrcpyForm(string DeviceName, Process ScrcpyProcess)
23 | {
24 |
25 | this.ScrcpyProcess = ScrcpyProcess;
26 | this.DeviceName= DeviceName;
27 | InitializeComponent();
28 | }
29 |
30 | private void ScrcpyForm_Load(object sender, EventArgs e)
31 | {
32 | childHwnd = ScrcpyProcess.MainWindowHandle;
33 | ProcessWindowController.SetParent(childHwnd, this.panel1.Handle);
34 |
35 | ProcessWindowController.RECT fx = new ProcessWindowController.RECT();
36 |
37 | ProcessWindowController.GetWindowRect(childHwnd, ref fx);
38 | int width = fx.Right - fx.Left; //窗口的宽度
39 | int height = fx.Bottom - fx.Top; //窗口的高度
40 | int x = fx.Left;
41 | int y = fx.Top;
42 |
43 | ProcessWindowController.MoveWindow(childHwnd,
44 | -10, -30,
45 | this.panel1.Width + 20, this.panel1.Height + 30, true);
46 |
47 | tooltipComponent1.SetTip(home_btn, "主页");
48 | tooltipComponent1.SetTip(back_btn, "返回");
49 | //tooltipComponent1.SetTip(home_btn, "主页");
50 | //tooltipComponent1.SetTip(home_btn, "主页");
51 |
52 | }
53 |
54 |
55 |
56 | private void ScrcpyForm_FormClosing(object sender, FormClosingEventArgs e)
57 | {
58 | //ScrcpyProcess.Kill();
59 | if (e.CloseReason == CloseReason.UserClosing)
60 | {
61 | e.Cancel = true;
62 |
63 | this.Hide();
64 | //notifyIcon1.Visible = true;
65 | }
66 | }
67 |
68 |
69 |
70 | private void ScrcpyForm_Resize(object sender, EventArgs e)
71 | {
72 |
73 | int width = this.panel1.Width;
74 | int height = this.panel1.Height;
75 | ProcessWindowController.MoveWindow(childHwnd,
76 | -10, -30,
77 | width+20, height+30, true);
78 | }
79 |
80 | private void inputNumber1_ValueChanged(object sender, decimal value)
81 | {
82 |
83 | ScrcpyForm_Resize(null, null);
84 | }
85 |
86 | private void home_btn_Click(object sender, EventArgs e)
87 | {
88 | new DeviceADB(DeviceName).SendHome();
89 | }
90 |
91 | private void back_btn_Click(object sender, EventArgs e)
92 | {
93 | new DeviceADB(DeviceName).SendKeyEvent(ADBKey.Key.KEYCODE_BACK);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/ScrcpySetting.cs:
--------------------------------------------------------------------------------
1 | using AntdUI;
2 | using MobileControlGuru.Base;
3 | using MobileControlGuru.Properties;
4 | using MobileControlGuru.Tools;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.ComponentModel;
8 | using System.Data;
9 | using System.Drawing;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 | using System.Windows.Forms;
14 | using static System.Windows.Forms.VisualStyles.VisualStyleElement;
15 |
16 | namespace MobileControlGuru
17 | {
18 | public partial class ScrcpySetting : BaseForm
19 | {
20 | public ScrcpySetting()
21 | {
22 | InitializeComponent();
23 | resources = new ComponentResourceManager(typeof(ScrcpySetting));
24 | }
25 |
26 | public void GetParams()
27 | {
28 | ScrcpyParam scrcpyParam = new ScrcpyParam() {
29 |
30 | NoAudio= NoAudioSwitch.Checked,
31 | WindowHeight=WindowHeightInput.Text,
32 | WindowWidth=WindowWidthInput.Text,
33 | WindowX=WindowXInput.Text,
34 | WindowY=WindowYInput.Text,
35 | KeyboardUhid= KeyboardUhidSwitch.Checked,
36 | TurnScreenOff=turn_screen_off.Checked,
37 | StayAwake=stay_awake.Checked,
38 | AlwaysOnTop= AlwaysOnTop.Checked
39 | };
40 |
41 | ConfigHelp.SetSetting("ScrcpyParamObj", JsonHelp.Obj2Str(scrcpyParam));
42 | this.Close();
43 | //return "";
44 | }
45 |
46 | private void button1_Click(object sender, EventArgs e)
47 | {
48 | GetParams();
49 | }
50 |
51 | private void ScrcpySetting_Load(object sender, EventArgs e)
52 | {
53 | var scrcpyParam= JsonHelp.Str2Obj (ConfigHelp.GetConfig("ScrcpyParamObj"));
54 |
55 | if(scrcpyParam != null)
56 | {
57 | NoAudioSwitch.Checked = scrcpyParam.NoAudio;
58 | WindowHeightInput.Text = scrcpyParam.WindowHeight;
59 | WindowWidthInput.Text= scrcpyParam.WindowWidth;
60 | WindowXInput.Text= scrcpyParam.WindowX;
61 | WindowYInput.Text= scrcpyParam.WindowY;
62 | KeyboardUhidSwitch.Checked = scrcpyParam.KeyboardUhid;
63 | turn_screen_off.Checked= scrcpyParam.TurnScreenOff;
64 | stay_awake.Checked= scrcpyParam.StayAwake ;
65 | AlwaysOnTop.Checked= scrcpyParam.AlwaysOnTop;
66 | }
67 | var lang = Tools.ConfigHelp.GetConfig("Lang");
68 | if (!string.IsNullOrEmpty(lang))
69 | {
70 | ChangeLang(lang);
71 | ApplyResource();
72 | }
73 | }
74 |
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Src/DeviceADB.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Base;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace MobileControlGuru.Src
13 | {
14 | ///
15 | /// 设备ADB操作类
16 | ///
17 | public class DeviceADB
18 | {
19 | public string DeviceName { set; get; }
20 |
21 | public DeviceADB(string deviceName)
22 | {
23 | if (Common.IsValidIP(deviceName)) {
24 | DeviceName = GetDevice(deviceName);
25 | }
26 | else
27 | {
28 | DeviceName = deviceName;
29 | }
30 |
31 | }
32 | ///
33 | /// 检查设备在线状态
34 | ///
35 | ///
36 | public bool CheckOnline()
37 | {
38 | Model.Device d = null;
39 | if (Common.IsValidIP(DeviceName))
40 | {
41 | DeviceName = DeviceName.Split(':')[0]+":";
42 | }
43 | d = DeviceManager.Instance.devices.Where(n =>n.Status=="device"&& n.Name.StartsWith(DeviceName)).FirstOrDefault();
44 |
45 | return d!=null;
46 | }
47 | ///
48 | /// 获取设备,如果是ip设备责只关心ip不关心端口号
49 | ///
50 | ///
51 | ///
52 | public string GetDevice(string deviceIP)
53 | {
54 | deviceIP= deviceIP.Split(':')[0];
55 | var d= DeviceManager.Instance.devices.Where(n=>n.Name.StartsWith(deviceIP+":")).FirstOrDefault();
56 | return d.Name;
57 | }
58 | ///
59 | /// 发送按键
60 | ///
61 | ///
62 | ///
63 | public AdbParse SendKeyEvent( ADBKey.Key key)
64 | {
65 |
66 | var res = ADB.Exec($"-s {DeviceName} shell input keyevent {key}");
67 |
68 | return res;
69 |
70 | }
71 | ///
72 | /// 发送按键
73 | ///
74 | ///
75 | ///
76 | public AdbParse SendKeyEvent( string key)
77 | {
78 |
79 | var res = ADB.Exec($"-s {DeviceName} shell input keyevent {key}");
80 | return res;
81 | }
82 | ///
83 | /// 发送滑动命令
84 | ///
85 | ///
86 | ///
87 | ///
88 | ///
89 | public AdbParse SendSwipe(Point form, Point to, int delta = 100)
90 | {
91 | var res = ADB.Exec($"-s {DeviceName} shell input swipe {form.X} {form.Y} {to.X} {to.Y} {delta}");
92 | return res;
93 | }
94 |
95 | ///
96 | /// 下滑
97 | ///
98 | ///
99 | public AdbParse SendSwipeDown()
100 | {
101 | var res = SendSwipe( new Point(540, 500), new Point(540, 1300));
102 | return res;
103 | }
104 | ///
105 | /// 上滑
106 | ///
107 | ///
108 | public AdbParse SendSwipeUp()
109 | {
110 | var res = SendSwipe( new Point(540, 1300), new Point(540, 500));
111 | return res;
112 | }
113 | ///
114 | /// 发送锁屏
115 | ///
116 | ///
117 | public AdbParse SendLock()
118 | {
119 | var res =SendKeyEvent(ADBKey.Key.KEYCODE_POWER);
120 | return res;
121 | }
122 | public AdbParse SendHome()
123 | {
124 | var res = SendKeyEvent(ADBKey.Key.KEYCODE_HOME);
125 | return res;
126 | }
127 | public AdbParse TapScreen(Point point)
128 | {
129 | var res = ADB.Exec($"-s {DeviceName} shell input tap {point.X} {point.Y} ");
130 | return res;
131 | }
132 |
133 |
134 | public AdbParse ScreenCap()
135 | {
136 | var basepath = ConfigHelp.GetConfig("DeivesDir");
137 | if(basepath == null)
138 | {
139 | basepath = Directory.GetCurrentDirectory();
140 | ConfigHelp.SetSetting("DeivesDir", basepath);
141 | }
142 |
143 |
144 | var pathDir = Path.Combine(basepath, GetOkFileName(DeviceName), "ScreenCap");
145 | if (!Directory.Exists(pathDir)) {
146 | Directory.CreateDirectory(pathDir);
147 | }
148 |
149 | var savePath = Path.Combine(pathDir, DateTime.Now.ToString("yyyyMMdd_HHmmssfff") + ".png");
150 | var res= ADB.Screencap(DeviceName, savePath);
151 | return res;
152 | }
153 |
154 | private string GetOkFileName(string strFile)
155 | {
156 | //string strFileName = "文件名称";
157 | StringBuilder rBuilder = new StringBuilder(strFile);
158 | foreach (char rInvalidChar in Path.GetInvalidFileNameChars())
159 | rBuilder.Replace(rInvalidChar.ToString(), string.Empty);
160 |
161 | strFile = rBuilder.ToString().Trim();
162 | strFile = strFile.Replace("+", "");
163 | return strFile;
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/Src/DeviceManager.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Base;
2 | using MobileControlGuru.Model;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace MobileControlGuru.Src
12 | {
13 | ///
14 | /// 全局设备管理类
15 | ///
16 | public class DeviceManager
17 | {
18 | public delegate void UpdateDelegate();
19 |
20 | ///
21 | /// 更行设备信息委托
22 | ///
23 | public UpdateDelegate updateDelegates;
24 | public List devices { set; get; }
25 |
26 | private static DeviceManager instance = null;
27 | private static readonly object lockObj = new object();
28 |
29 | private DeviceManager() { }
30 | ///
31 | /// 单例模式
32 | ///
33 | public static DeviceManager Instance
34 | {
35 | get
36 | {
37 | if (instance == null)
38 | {
39 | lock (lockObj)
40 | {
41 | if (instance == null)
42 | {
43 | instance = new DeviceManager();
44 | instance.devices = new List();
45 | }
46 | }
47 | }
48 | return instance;
49 | }
50 | }
51 |
52 |
53 | ///
54 | /// 更新设备列表
55 | ///
56 | public void UpdateDevices()
57 | {
58 | var data = ADB.GetDeiveces();
59 |
60 | List newDevices = data.Select(n => n.Name).ToList();
61 | List oldDevices = DeviceManager.Instance.devices.Select(n => n.Name).ToList();
62 |
63 | //删除不在的
64 | var needRemove = DeviceManager.Instance.devices.Where(n => !newDevices.Contains(n.Name)).ToList();
65 | foreach (var r in needRemove)
66 | {
67 | if (r.ScrcpyProcess != null)
68 | {
69 | r.ScrcpyProcess.Dispose();
70 | }
71 | DeviceManager.Instance.devices.Remove(r);
72 | }
73 | //添加新的
74 | var addItems = data.Where(n => !oldDevices.Contains(n.Name)).ToList();
75 | DeviceManager.Instance.devices = DeviceManager.Instance.devices.Concat(addItems).OrderByDescending(n=>n.IsTop).ToList();
76 |
77 | //状态更新
78 | foreach(var r in DeviceManager.Instance.devices)
79 | {
80 | var d=data.Where(n=>n.Name == r.Name).FirstOrDefault();
81 | if(d != null)
82 | {
83 | r.Status=d.Status;
84 | }
85 | }
86 |
87 |
88 | updateDelegates();
89 | }
90 | ///
91 | /// 绑定scrcpy 到设备
92 | ///
93 | ///
94 | ///
95 | public void BindDevicesProcees(string devicename, Process process)
96 | {
97 |
98 | var d = GetDevice(devicename);
99 | d.ScrcpyProcess = process;
100 | d.ScrcpyProcess.Exited += new EventHandler(exitHandle);
101 | updateDelegates();
102 | }
103 | ///
104 | /// scrcpy 进程退出事件
105 | ///
106 | ///
107 | ///
108 | private void exitHandle(object sender, EventArgs e)
109 | {
110 | var p = (Process)sender;
111 | var d = DeviceManager.Instance.devices.
112 | Where(n => n.ScrcpyProcess != null && n.ScrcpyProcess.Id == p.Id).FirstOrDefault();
113 | if (d != null)
114 | {
115 | d.ScrcpyProcess = null;
116 | if (d.monitor != null)
117 | {
118 | d.monitor.Stop();
119 | }
120 |
121 | }
122 | DeviceManager.Instance.UpdateDevices();
123 | }
124 |
125 | public Device GetDevice(string name)
126 | {
127 | var d = DeviceManager.Instance.devices.Where(n => n.Name == name).FirstOrDefault();
128 | return d;
129 |
130 | }
131 |
132 |
133 | public void CloseAll()
134 | {
135 | foreach(var d in devices)
136 | {
137 | Close(d);
138 |
139 | }
140 | }
141 | public void Close(Device d)
142 | {
143 |
144 | if (d.monitor != null)
145 | {
146 | d.monitor.Stop();
147 | }
148 | if (d.ScrcpyProcess != null)
149 | {
150 | if (!d.ScrcpyProcess.HasExited)
151 | {
152 | d.ScrcpyProcess.Kill(); // 强制结束进程
153 | }
154 |
155 | }
156 |
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/Src/ScrcpyMonitor.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Model;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using static MobileControlGuru.Base.ProcessWindowController;
10 | namespace MobileControlGuru.Src
11 | {
12 | public class ScrcpyMonitor
13 | {
14 | public Device Device { get {
15 | return DeviceManager.Instance.GetDevice(DeviceName);
16 | }
17 | }
18 | public string DeviceName { get; set; }
19 | public MainForm main { set; get; }
20 | IntPtr hook { get; set; }
21 | GCHandle handle { get; set; }
22 | public ScrcpyMonitor(string DeviceName)
23 | {
24 | this.DeviceName = DeviceName;
25 | }
26 |
27 | public void Start()
28 | {
29 | if (Device.ScrcpyProcess == null)
30 | {
31 | return;
32 | }
33 | WinEventDelegate myDelegate = WinEventProc;
34 | handle = GCHandle.Alloc(myDelegate);
35 | hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_OBJECT_LOCATIONCHANGE,
36 | IntPtr.Zero,(WinEventDelegate)handle.Target, (uint)Device.ScrcpyProcess.Id, 0, WINEVENT_OUTOFCONTEXT);
37 |
38 | if (hook == IntPtr.Zero)
39 | {
40 | LogHelper.Error($"Failed to set WinEventHook. Error: {Marshal.GetLastWin32Error()}");
41 | return;
42 | }
43 | }
44 |
45 |
46 | public void Stop()
47 | {
48 | if (hook != IntPtr.Zero)
49 | {
50 | UnhookWinEvent(hook);
51 |
52 | }
53 | if (handle.IsAllocated)
54 | handle.Free();
55 |
56 | }
57 |
58 | public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
59 | {
60 | uint processId;
61 | var a= Device.Name;
62 | GetWindowThreadProcessId(hwnd, out processId);
63 | if (processId == 0)
64 | return; // Not the target process's window
65 | RECT fx = new RECT();
66 | switch (eventType)
67 | {
68 | case EVENT_SYSTEM_FOREGROUND:
69 | fx = new RECT();
70 | GetWindowRect(hwnd, ref fx);//h为窗口句柄
71 | main.SetControl(fx);
72 | main.ShowControl(Device);
73 | Console.WriteLine(a + $"Target window was activated.type: {eventType} time:" + DateTime.Now);
74 | break;
75 | case EVENT_OBJECT_LOCATIONCHANGE:
76 | fx = new RECT();
77 | GetWindowRect(hwnd, ref fx);//h为窗口句柄
78 | main.SetControl(fx);
79 | Console.WriteLine(a + $"Target window was moved.type: {eventType} time:" + DateTime.Now);
80 | break;
81 | default:
82 | Console.WriteLine($"{a} Unknown event type: {eventType} time:" + DateTime.Now);
83 | break;
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Src/TaskManager.cs:
--------------------------------------------------------------------------------
1 | using Quartz;
2 | using Quartz.Impl;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MobileControlGuru.Src
10 | {
11 | ///
12 | /// 任务管理
13 | ///
14 | public class TaskManager
15 | {
16 | private static TaskManager instance = null;
17 | private static readonly object lockObj = new object();
18 | private TaskManager() {
19 |
20 |
21 | factory = new StdSchedulerFactory();
22 |
23 | }
24 | ///
25 | /// 单例模式
26 | ///
27 | public static TaskManager Instance
28 | {
29 | get
30 | {
31 | if (instance == null)
32 | {
33 | lock (lockObj)
34 | {
35 | if (instance == null)
36 | {
37 | instance = new TaskManager();
38 | }
39 | }
40 | }
41 | return instance;
42 | }
43 | }
44 |
45 | StdSchedulerFactory factory ;
46 | IScheduler scheduler;
47 |
48 |
49 | public async void Start()
50 | {
51 |
52 | scheduler= await factory.GetScheduler();
53 | await scheduler.Start();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Tools/Common.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.RegularExpressions;
6 | using System.Threading.Tasks;
7 |
8 | namespace MobileControlGuru.Tools
9 | {
10 | public class Common
11 | {
12 | public static bool IsValidIP(string input)
13 | {
14 | // 匹配IP地址,后面可选地跟一个冒号和1-65535之间的端口号
15 | string pattern = @"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(:[1-9][0-9]{1,4})?$";
16 |
17 | return Regex.IsMatch(input, pattern);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Tools/ConfigHelp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MobileControlGuru.Tools
9 | {
10 | public class ConfigHelp
11 | {
12 | public static string GetConfig(string key)
13 | {
14 | Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
15 | var c = config.AppSettings.Settings[key];
16 | if (c == null)
17 | {
18 | return "";
19 | }
20 | else
21 | {
22 | return c.Value;
23 | }
24 |
25 |
26 | }
27 | public static void SetSetting(string key, string value)
28 | {
29 | if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
30 | {
31 | Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
32 |
33 | // 如果键已经存在,则更新值
34 | if (config.AppSettings.Settings[key] != null)
35 | {
36 | config.AppSettings.Settings[key].Value = value;
37 | }
38 | // 否则,添加新的键值对
39 | else
40 | {
41 | config.AppSettings.Settings.Add(key, value);
42 | }
43 |
44 | config.Save(ConfigurationSaveMode.Modified); // 保存更改
45 | ConfigurationManager.RefreshSection("appSettings"); // 刷新配置,使得更改立即生效
46 | }
47 | else
48 | {
49 | throw new ArgumentException("Both Key and Value must have a non-null, non-empty value.");
50 | }
51 | }
52 |
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/Tools/JsonHelp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Web.Script.Serialization;
7 | namespace MobileControlGuru.Tools
8 | {
9 | public class JsonHelp
10 | {
11 |
12 | public static T Str2Obj(string input)
13 | {
14 | return new JavaScriptSerializer().Deserialize(input);
15 | }
16 |
17 | public static string Obj2Str(object obj)
18 | {
19 | return new JavaScriptSerializer().Serialize(obj);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Tools/LanguageHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Forms;
8 |
9 | namespace MobileControlGuru.Tools
10 | {
11 | public class LanguageHelper
12 | {
13 |
14 | #region SetAllLang
15 | ///
16 | /// Set language
17 | ///
18 | /// language:zh-CN, en-US
19 | private static void SetAllLang(string lang)
20 | {
21 | System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang);
22 | Form frm = null;
23 |
24 | string name = "MainForm";
25 |
26 | frm = (Form)Assembly.Load("CameraTest").CreateInstance(name);
27 |
28 | if (frm != null)
29 | {
30 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager();
31 | resources.ApplyResources(frm, "$this");
32 | AppLang(frm, resources);
33 | }
34 | }
35 | #endregion
36 |
37 | #region SetLang
38 | ///
39 | ///
40 | ///
41 | /// language:zh-CN, en-US
42 | /// the form you need to set
43 | /// the type of the form
44 | public static void SetLang(string lang, Form form, Type formType)
45 | {
46 | System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang);
47 | if (form != null)
48 | {
49 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(formType);
50 | resources.ApplyResources(form, "$this");
51 | AppLang(form, resources);
52 | }
53 | }
54 | #endregion
55 |
56 | #region AppLang for control
57 | ///
58 | /// loop set the propery of the control
59 | ///
60 | ///
61 | ///
62 | private static void AppLang(Control control, System.ComponentModel.ComponentResourceManager resources)
63 | {
64 | if (control is MenuStrip)
65 | {
66 | resources.ApplyResources(control, control.Name);
67 | MenuStrip ms = (MenuStrip)control;
68 | if (ms.Items.Count > 0)
69 | {
70 | foreach (ToolStripMenuItem c in ms.Items)
71 | {
72 | AppLang(c, resources);
73 | }
74 | }
75 | }
76 |
77 | foreach (Control c in control.Controls)
78 | {
79 | resources.ApplyResources(c, c.Name);
80 | AppLang(c, resources);
81 | }
82 | }
83 | #endregion
84 |
85 | #region AppLang for menuitem
86 | ///
87 | /// set the toolscript
88 | ///
89 | ///
90 | ///
91 | private static void AppLang(ToolStripMenuItem item, System.ComponentModel.ComponentResourceManager resources)
92 | {
93 | if (item is ToolStripMenuItem)
94 | {
95 | resources.ApplyResources(item, item.Name);
96 | ToolStripMenuItem tsmi = (ToolStripMenuItem)item;
97 | if (tsmi.DropDownItems.Count > 0)
98 | {
99 | foreach (ToolStripMenuItem c in tsmi.DropDownItems)
100 | {
101 | AppLang(c, resources);
102 | }
103 | }
104 | }
105 | }
106 | #endregion
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/Tools/LogHelper.cs:
--------------------------------------------------------------------------------
1 | using log4net;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | [assembly: log4net.Config.XmlConfigurator()]
9 | namespace MobileControlGuru.Tools
10 | {
11 |
12 | public class LogHelper
13 | {
14 |
15 | static readonly ILog _logger = LogManager.GetLogger("LogTrace");
16 | public static void Info(string message)
17 | {
18 | _logger.Info(message); //打印事件
19 | }
20 |
21 | public static void Debug(string message)
22 | {
23 | _logger.Debug(message); //调试
24 | }
25 |
26 | public static void Warn(string message)
27 | {
28 | _logger.Warn(message); //警告
29 | }
30 |
31 | public static void Error(string message)
32 | {
33 | _logger.Error(message); //错误
34 | }
35 | public static void Error(Exception ex, string memo = "")
36 | {
37 | _logger.Error(FormatExceptionDetails(ex, memo));
38 | }
39 | ///
40 | /// 格式化异常信息
41 | ///
42 | ///
43 | ///
44 | ///
45 | public static string FormatExceptionDetails(Exception ex, string memo = "")
46 | {
47 | StringBuilder sb = new StringBuilder();
48 |
49 | // 异常基本信息
50 | sb.AppendLine(memo + "Exception Details:");
51 | sb.AppendLine($"Exception Type: {ex.GetType().FullName}");
52 | sb.AppendLine($"Message: {ex.Message}");
53 | if (!string.IsNullOrEmpty(ex.Source))
54 | sb.AppendLine($"Source: {ex.Source}");
55 |
56 | // 堆栈跟踪
57 | sb.AppendLine("Stack Trace:");
58 | sb.AppendLine(ex.StackTrace);
59 |
60 | // 内部异常
61 | Exception innerEx = ex.InnerException;
62 | while (innerEx != null)
63 | {
64 | sb.AppendLine();
65 | sb.AppendLine("Inner Exception:");
66 | sb.AppendLine($"Exception Type: {innerEx.GetType().FullName}");
67 | sb.AppendLine($"Message: {innerEx.Message}");
68 | if (!string.IsNullOrEmpty(innerEx.Source))
69 | sb.AppendLine($"Source: {innerEx.Source}");
70 | sb.AppendLine(innerEx.StackTrace);
71 | innerEx = innerEx.InnerException;
72 | }
73 |
74 | // (可选)添加自定义上下文信息,如当前时间、线程ID等
75 | sb.AppendLine();
76 | sb.AppendLine($"Time: {DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC")}");
77 | sb.AppendLine($"Thread ID: {Thread.CurrentThread.ManagedThreadId}");
78 |
79 | return sb.ToString();
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Tools/ZipHelper.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Properties;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO.Compression;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MobileControlGuru.Tools
11 | {
12 | public class ZipHelper
13 | {
14 | public static void ExtractZipToDirectory(string outputDirectory)
15 | {
16 |
17 | byte[] zipBytes = Resources.scrcpy; // 获取 ZIP 文件的字节数组
18 |
19 | // 确保输出目录存在
20 | Directory.CreateDirectory(outputDirectory);
21 |
22 | // 创建一个临时 ZIP 文件
23 | string tempZipPath = Path.GetTempFileName();
24 | try
25 | {
26 | // 将字节数组写入临时 ZIP 文件
27 | File.WriteAllBytes(tempZipPath, zipBytes);
28 |
29 | // 使用 ZipFile 解压临时 ZIP 文件到指定的输出目录
30 | ZipFile.ExtractToDirectory(tempZipPath, outputDirectory);
31 | }
32 | catch(Exception e)
33 | {
34 |
35 | }
36 | finally
37 | {
38 | // 删除临时 ZIP 文件
39 | File.Delete(tempZipPath);
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/WebAPI/Controllers/DeviceController.cs:
--------------------------------------------------------------------------------
1 | using MobileControlGuru.Base;
2 | using MobileControlGuru.Src;
3 | using MobileControlGuru.Tools;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Web.Http;
11 |
12 | namespace MobileControlGuru.WebAPI.Controllers
13 | {
14 | public class DeviceController : ApiController
15 | {
16 | ///
17 | /// 设备列表
18 | ///
19 | ///
20 | [HttpGet]
21 | public string List()
22 | {
23 | return string.Join(",", DeviceManager.Instance.devices.Select(n => n.Name));
24 |
25 | }
26 |
27 | ///
28 | /// 检查设备在线情况
29 | ///
30 | ///
31 | ///
32 | [HttpGet]
33 | public string CheckOnline(string devicename)
34 | {
35 | if(new DeviceADB(devicename).CheckOnline())
36 | {
37 | return "online";
38 | }
39 | else
40 | {
41 | return "offline";
42 | }
43 | }
44 | ///
45 | /// 连接设备
46 | ///
47 | /// 设备名/IP
48 | ///
49 | [HttpGet]
50 | public string Connect(string devicename)
51 | {
52 |
53 | var res= ADB.Connect(devicename);
54 |
55 | return res.Message;
56 | }
57 |
58 | ///
59 | /// 无线授权调试
60 | ///
61 | /// 设备IP
62 | /// 端口号
63 | /// 6位配对码
64 | ///
65 | [HttpGet]
66 | public string Pair(string devicename,int port,int code)
67 | {
68 |
69 | var res = ADB.Pair(devicename,port,code);
70 |
71 | return res.Message;
72 | }
73 |
74 | ///
75 | /// 发送锁屏键
76 | ///
77 | /// 设备名/IP
78 | ///
79 | [HttpGet]
80 | public string Lock(string devicename)
81 | {
82 | var res = new DeviceADB(devicename).SendLock();
83 | return res.Message;
84 | }
85 |
86 |
87 | ///
88 | /// 发送自定义按键
89 | ///
90 | /// 设备名/IP
91 | /// 按键范围应当在正常的范围内
92 | ///
93 | [HttpGet]
94 | public string SendKey(string devicename,string Key)
95 | {
96 |
97 | var res = new DeviceADB(devicename).SendKeyEvent( Key);
98 | return res.Message;
99 | }
100 | ///
101 | /// 屏幕滑动
102 | ///
103 | /// 设备名/IP
104 | /// up表示上滑,在短视频里就表示下一个
105 | ///
106 | [HttpGet]
107 | public string SendSwipe(string devicename, string direct)
108 | {
109 | var res = new AdbParse("","");
110 | if (direct == "up")
111 | {
112 | res= new DeviceADB(devicename).SendSwipeUp();
113 | }
114 | else
115 | {
116 | res= new DeviceADB(devicename).SendSwipeDown();
117 | }
118 |
119 | return res.Message;
120 | }
121 |
122 | ///
123 | /// 屏幕点击
124 | ///
125 | ///
126 | ///
127 | ///
128 | ///
129 | [HttpGet]
130 | public string SendTap(string devicename, int x,int y)
131 | {
132 | var res = new DeviceADB(devicename).TapScreen(new Point(x, y));
133 |
134 |
135 | return res.Message;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/WebAPI/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Web.Http;
7 |
8 | namespace MobileControlGuru.WebAPI.Controllers
9 | {
10 |
11 |
12 | public class HomeController : ApiController
13 | {
14 |
15 |
16 | public string Index() {
17 |
18 | return "opened";
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/WebAPI/Startup.cs:
--------------------------------------------------------------------------------
1 | using Owin;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net.Http.Formatting;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Web.Http;
9 | using Swashbuckle.Application;
10 | using static System.Windows.Forms.Design.AxImporter;
11 | using System.IO;
12 | using System.Reflection;
13 |
14 | namespace MobileControlGuru.WebAPI
15 | {
16 | public class Startup
17 | {
18 | public void Configuration(IAppBuilder appBuilder)
19 | {
20 | HttpConfiguration config = new HttpConfiguration();
21 | config.MapHttpAttributeRoutes();
22 | config.Routes.MapHttpRoute(name: "DefaultApi",
23 | routeTemplate: "api/{controller}/{action}",
24 | defaults: new {
25 | controller = "Home",
26 | action = "Index",
27 | id = RouteParameter.Optional
28 | }
29 | );
30 | config
31 | .EnableSwagger(c => {
32 | c.SingleApiVersion("v1", "mobile control guru api");
33 | c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
34 | var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
35 |
36 | var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".XML";
37 | var commentsFile = Path.Combine(baseDirectory, commentsFileName);
38 | c.IncludeXmlComments(commentsFile);
39 | })
40 | .EnableSwaggerUi();
41 |
42 | //清除xml格式,使用json格式
43 | config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
44 | config.Formatters.Add(new JsonMediaTypeFormatter());
45 |
46 |
47 |
48 | appBuilder.UseWebApi(config);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/WebAPI/WebHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Owin.Hosting;
2 | using MobileControlGuru.Tools;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Net.Sockets;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Web;
11 |
12 | namespace MobileControlGuru.WebAPI
13 | {
14 | public class WebHelper
15 | {
16 | public string Port { set; get; }
17 | public bool Runnig { set; get; }
18 | IDisposable myOwinServer;
19 |
20 | public string Url { set; get; }
21 |
22 | public WebHelper(string port)
23 | {
24 | if (string.IsNullOrEmpty(port))
25 | {
26 | Port = port;
27 | }else
28 | if (string.IsNullOrEmpty(ConfigHelp.GetConfig("WebPort")))
29 | {
30 | Port = ConfigHelp.GetConfig("WebPort");
31 | }
32 | else
33 | {
34 | Port = "12345";
35 | }
36 | }
37 |
38 | public WebHelper()
39 | {
40 | if (string.IsNullOrEmpty(ConfigHelp.GetConfig("WebPort")))
41 | {
42 | Port = ConfigHelp.GetConfig("WebPort");
43 | }
44 | else
45 | {
46 | Port = "12345";
47 | }
48 | }
49 |
50 | public void Run()
51 | {
52 | int port = Convert.ToInt32(Port);
53 | StartOptions options = new StartOptions();
54 | Url = "http://localhost:" + port;
55 |
56 | // options.Urls.Add(Url);
57 | options.Urls.Add("http://+:" + port);
58 |
59 | myOwinServer = WebApp.Start(options);
60 |
61 |
62 | }
63 | public void Dispose()
64 | {
65 |
66 | myOwinServer?.Dispose();
67 | Runnig = false;
68 | }
69 |
70 |
71 |
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/adb_cmds.txt:
--------------------------------------------------------------------------------
1 | #获取设备 ip
2 | #192.168.191.0/24 dev wlan0 proto kernel scope link src 192.168.191.3
3 | shell ip route
4 |
5 | #
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------