From 08eddf204a6bf0fa984ab8e60f01c665cd5c0a17 Mon Sep 17 00:00:00 2001
From: pdone <617941447@qq.com>
Date: Fri, 19 Jan 2024 16:13:40 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=95=BF=E6=97=B6=E9=97=B4?=
=?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=90=8E=E5=85=B3=E9=97=AD=E7=AA=97=E5=8F=A3?=
=?UTF-8?q?=E4=B8=8D=E5=BC=B9=E5=87=BA=E4=B8=BB=E7=95=8C=E9=9D=A2=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98=20#58?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FreeControl/Controller.Designer.cs | 2 +-
FreeControl/Controller.cs | 18 ++--
FreeControl/Main.cs | 82 ++++++++++-------
FreeControl/Properties/AssemblyInfo.cs | 4 +-
FreeControl/Setting.cs | 10 +++
FreeControl/Update.en.md | 4 +
FreeControl/Update.md | 4 +
FreeControl/Utils/ADB.cs | 2 +-
FreeControl/Utils/JsonHelper.cs | 37 ++++----
FreeControl/Utils/MoveListener.cs | 119 ++++++++++++++++++++++++-
10 files changed, 214 insertions(+), 68 deletions(-)
diff --git a/FreeControl/Controller.Designer.cs b/FreeControl/Controller.Designer.cs
index 43c7396..894303e 100644
--- a/FreeControl/Controller.Designer.cs
+++ b/FreeControl/Controller.Designer.cs
@@ -194,7 +194,7 @@ private void InitializeComponent()
this.ShowRadius = false;
this.ShowTitle = false;
this.Text = "Controller";
- this.TopMost = true;
+ this.TopMost = false;
this.flowPanel.ResumeLayout(false);
this.ResumeLayout(false);
diff --git a/FreeControl/Controller.cs b/FreeControl/Controller.cs
index ad85920..2145fdc 100644
--- a/FreeControl/Controller.cs
+++ b/FreeControl/Controller.cs
@@ -19,15 +19,15 @@ public Controller()
///
/// 更新控制器位置
///
- public void UpdateLocation()
- {
- Action action = () =>
- {
- // 减去控制器自身默认宽度
- Location = new Point(Main._Setting.ScrcpyPointX - 57, Main._Setting.ScrcpyPointY);
- };
- Invoke(action);
- }
+ //public void UpdateLocation()
+ //{
+ // Action action = () =>
+ // {
+ // // 减去控制器自身默认宽度
+ // Location = new Point(Main._Setting.ScrcpyPointX - 57, Main._Setting.ScrcpyPointY);
+ // };
+ // Invoke(action);
+ //}
///
/// 初始化窗口大小和位置
diff --git a/FreeControl/Main.cs b/FreeControl/Main.cs
index d77f704..cbb6bfc 100644
--- a/FreeControl/Main.cs
+++ b/FreeControl/Main.cs
@@ -83,12 +83,17 @@ public class Info
public static string NameVersion { get; set; }
}
- public MultiLanguage i18n;
+ ///
+ /// 多语言支持
+ ///
+ public MultiLanguage I18n;
+
+ public static IntPtr ControllerPtr = IntPtr.Zero;
///
- /// 是否启用输入法切换
+ /// 保持后台活跃 避免界面隐藏后被自动回收
///
- public readonly bool EnableSwitchIME = false;
+ private readonly System.Timers.Timer _Timer;
#endregion
#region 构造函数
@@ -99,12 +104,20 @@ public Main()
{
// 获取用户配置数据
_Setting = GetUserData();
- LoadResEn();
-
+ // 加载语言资源
+ LoadLangRes();
+ // 设置语言
string lang = _Setting.Language.GetDesc();
- i18n = new MultiLanguage(_Setting.Language);
+ I18n = new MultiLanguage(_Setting.Language);
System.Globalization.CultureInfo UICulture = new System.Globalization.CultureInfo(lang);
Thread.CurrentThread.CurrentUICulture = UICulture;
+ // 界面保活
+ _Timer = new System.Timers.Timer(_Setting.Heartbeat);
+ _Timer.Elapsed += (sender, e) =>
+ {
+ Logger.Info("", "alive");
+ };
+
InitializeComponent();
InitPdone();
IsInit = false;
@@ -135,10 +148,10 @@ public static Setting GetUserData()
Directory.CreateDirectory(UserDataPath);
if (!File.Exists(fullPath))
{
- File.WriteAllText(fullPath, JsonHelper.json(tempData));
+ File.WriteAllText(fullPath, JsonHelper.Obj2Str(tempData));
}
StreamReader reader = File.OpenText(fullPath);
- tempData = JsonHelper.jsonDes(reader.ReadToEnd());
+ tempData = JsonHelper.Str2Obj(reader.ReadToEnd());
reader.Close();
return tempData;
}
@@ -158,7 +171,7 @@ public static void SetUserData(Setting userData)
{
var fullPath = Path.Combine(UserDataPath, "config.json");
Directory.CreateDirectory(UserDataPath);
- File.WriteAllText(fullPath, JsonHelper.json(userData));
+ File.WriteAllText(fullPath, JsonHelper.Obj2Str(userData));
}
catch (Exception ex)
{
@@ -197,8 +210,8 @@ public void InitPdone()
}
#region 控件状态
- uiLabel7.Visible = EnableSwitchIME;
- linkIME.Visible = EnableSwitchIME;
+ uiLabel7.Visible = _Setting.EnableSwitchIME;
+ linkIME.Visible = _Setting.EnableSwitchIME;
#endregion
#region 事件绑定
@@ -280,9 +293,9 @@ public void InitPdone()
#endregion
#region 配置项默认值
- comboPx.Items[0] = i18n.def;
- comboMbps.Items[0] = i18n.def;
- comboMaxFPS.Items[0] = i18n.def;
+ comboPx.Items[0] = I18n.def;
+ comboMbps.Items[0] = I18n.def;
+ comboMaxFPS.Items[0] = I18n.def;
comboPx.SelectedIndex = _Setting.PXIndex;
comboMbps.SelectedIndex = _Setting.BitRateIndex;
comboMaxFPS.SelectedIndex = _Setting.MaxFPSIndex;
@@ -305,9 +318,9 @@ public void InitPdone()
cbxShowTouches.Checked = _Setting.ShowTouches;
cbxReadOnly.Checked = _Setting.ReadOnly;
cbxAudioEnabled.Checked = _Setting.AudioEnabled;
- linkIME.Text = i18n.imes[(InputMethod)_Setting.IME];
- tbxIp.Watermark = i18n.tbxIpPlaceholder;
- tbxPort.Watermark = i18n.tbxPortPlaceholder;
+ linkIME.Text = I18n.imes[(InputMethod)_Setting.IME];
+ tbxIp.Watermark = I18n.tbxIpPlaceholder;
+ tbxPort.Watermark = I18n.tbxPortPlaceholder;
#endregion
}
@@ -334,9 +347,9 @@ private void ExtractResource(bool reload = false)
}
///
- /// 加载英文资源
+ /// 加载语言资源 此资源控制界面布局
///
- public void LoadResEn()
+ public void LoadLangRes()
{
if (_Setting.Language == Lang.en)
{
@@ -365,7 +378,7 @@ private void StartButtonClick(object sender, EventArgs e)
if (_Setting.UseWireless &&
(string.IsNullOrWhiteSpace(_Setting.IPAddress) || string.IsNullOrWhiteSpace(_Setting.Port)))
{
- ShowMessage(i18n.msgIpNull);
+ ShowMessage(I18n.msgIpNull);
return;
}
@@ -511,7 +524,7 @@ private void RunScrcpy()
scrcpy.Exited += (ss, ee) =>
{
SetUserData(_Setting);// 关闭scrcpy后保存一下配置文件
- if (EnableSwitchIME && _Setting.IME != 0 && _Setting.IMEOrigin.IsNotNull())
+ if (_Setting.EnableSwitchIME && _Setting.IME != 0 && _Setting.IMEOrigin.IsNotNull())
{
ADB.Execute($"shell ime set {_Setting.IMEOrigin}");
}
@@ -519,12 +532,12 @@ private void RunScrcpy()
FromHandle(false);
ButtonHandle(false);
LoadHistoryIPs(true);
- ShowMessage(i18n.msgExit);
+ ShowMessage(I18n.msgExit);
};
scrcpy.BeginErrorReadLine();
scrcpy.BeginOutputReadLine();
- if (EnableSwitchIME && _Setting.IME != 0)
+ if (_Setting.EnableSwitchIME && _Setting.IME != 0)
{
// 获取当前输入法
string strCurIME = ADB.Execute($"adb shell settings get secure default_input_method");
@@ -562,12 +575,12 @@ private void ButtonHandle(bool isStart)
if (isStart)
{
btnStart.Enabled = false;
- btnStart.Text = i18n.btnStarting;
+ btnStart.Text = I18n.btnStarting;
}
else
{
btnStart.Enabled = true;
- btnStart.Text = i18n.btnStartDef;
+ btnStart.Text = I18n.btnStartDef;
}
};
Invoke(action);
@@ -588,8 +601,10 @@ private void FromHandle(bool isStart)
if (_Setting.ControllerEnabled)
{
_Controller = new Controller();
+ ControllerPtr = _Controller.Handle;
_Controller.Show();
}
+ _Timer?.Start();
}
else
{
@@ -597,6 +612,7 @@ private void FromHandle(bool isStart)
Show();
Activate();
Focus();
+ _Timer?.Stop();
}
};
Invoke(action);
@@ -621,7 +637,7 @@ void LoadHistoryIPs(bool isReload = false)
else
action();
}
-#endregion
+ #endregion
#region 配置项改变事件
///
@@ -903,7 +919,7 @@ private void linkEnabledADB_Click(object sender, EventArgs e)
private void linkSetPort_Click(object sender, EventArgs e)
{
- if (UIMessageBox.Show(i18n.linkSetPort, i18n.linkSetPortTitle,
+ if (UIMessageBox.Show(I18n.linkSetPort, I18n.linkSetPortTitle,
_Setting.DarkMode ? UIStyle.Black : UIStyle.Gray, UIMessageBoxButtons.OKCancel, false))
{
var batPath = ScrcpyPath + "SetProt.bat";
@@ -972,27 +988,27 @@ private void lbAllShortcut_Click(object sender, EventArgs e)
private void linkIME_Click(object sender, EventArgs e)
{
- var list = i18n.imes.Values.ToList();
+ var list = I18n.imes.Values.ToList();
int select = _Setting.IME;
- if (UISelectDialog.ShowSelectDialog(this, ref select, list, i18n.linkImeTitle, i18n.linkImeContent))
+ if (UISelectDialog.ShowSelectDialog(this, ref select, list, I18n.linkImeTitle, I18n.linkImeContent))
{
_Setting.IME = select;
- linkIME.Text = i18n.imes[(InputMethod)_Setting.IME];
+ linkIME.Text = I18n.imes[(InputMethod)_Setting.IME];
}
}
private void linkLang_Click(object sender, EventArgs e)
{
- var list = i18n.langs;
+ var list = I18n.langs;
int select = (int)_Setting.Language;
- if (UISelectDialog.ShowSelectDialog(this, ref select, list, i18n.linkLangTitle, i18n.linkLangContent))
+ if (UISelectDialog.ShowSelectDialog(this, ref select, list, I18n.linkLangTitle, I18n.linkLangContent))
{
if (select == (int)_Setting.Language)
{
return;
}
_Setting.Language = (Lang)select;
- LoadResEn();
+ LoadLangRes();
System.Windows.Forms.Application.Restart();
}
diff --git a/FreeControl/Properties/AssemblyInfo.cs b/FreeControl/Properties/AssemblyInfo.cs
index d6a1e84..51f2c18 100644
--- a/FreeControl/Properties/AssemblyInfo.cs
+++ b/FreeControl/Properties/AssemblyInfo.cs
@@ -33,5 +33,5 @@
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyVersion("1.0.0")]
-[assembly: AssemblyFileVersion("1.6.8")]
-[assembly: AssemblyVersion("1.6.8")]
+[assembly: AssemblyFileVersion("1.6.9")]
+[assembly: AssemblyVersion("1.6.9")]
diff --git a/FreeControl/Setting.cs b/FreeControl/Setting.cs
index 1b6b145..dfee016 100644
--- a/FreeControl/Setting.cs
+++ b/FreeControl/Setting.cs
@@ -173,6 +173,11 @@ public List ControllerButton
///
public string Version { get; set; } = "1.0.0";
+ ///
+ /// 是否启用输入法切换功能
+ ///
+ public bool EnableSwitchIME { get; set; } = false;
+
///
/// 启动Scrcpy时使用的输入法枚举值
///
@@ -196,5 +201,10 @@ public List ControllerButton
/// 主窗口 y坐标
///
public int MainWindowY { get; set; } = 0;
+
+ ///
+ /// 心跳间隔 单位:毫秒
+ ///
+ public int Heartbeat { get; set; } = 60000;
}
}
diff --git a/FreeControl/Update.en.md b/FreeControl/Update.en.md
index 00c329c..db2a9f4 100644
--- a/FreeControl/Update.en.md
+++ b/FreeControl/Update.en.md
@@ -1,5 +1,9 @@
# Free Control Update Record
+## v1.6.9
+- Fix bug
+- Some optimized
+
## v1.6.8
- Fix bug
- Remove automatic switching IME
diff --git a/FreeControl/Update.md b/FreeControl/Update.md
index 2d8cf07..df4286b 100644
--- a/FreeControl/Update.md
+++ b/FreeControl/Update.md
@@ -1,5 +1,9 @@
# Free Control 更新记录
+## v1.6.9
+- 修复了一些bug
+- 优化了代码
+
## v1.6.8
- 修复了一些bug
- 移除自动切换输入法功能
diff --git a/FreeControl/Utils/ADB.cs b/FreeControl/Utils/ADB.cs
index a4c9cd1..a383545 100644
--- a/FreeControl/Utils/ADB.cs
+++ b/FreeControl/Utils/ADB.cs
@@ -88,7 +88,7 @@ public static bool Screenshot()
///
public static void ExecuteShell(string command)
{
- Logger.Info($"{command}", $"ADB Shell");
+ Logger.Info($"{command}", $"adb shell");
var AdbProcessInfo = new ProcessStartInfo($"{ADBPath}adb.exe")
{
diff --git a/FreeControl/Utils/JsonHelper.cs b/FreeControl/Utils/JsonHelper.cs
index d21f8bc..7dd6c03 100644
--- a/FreeControl/Utils/JsonHelper.cs
+++ b/FreeControl/Utils/JsonHelper.cs
@@ -1,31 +1,28 @@
-//using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Web.Script.Serialization;
+using System.Web.Script.Serialization;
namespace FreeControl.Utils
{
public class JsonHelper
{
- ///
- /// json反序列化
- ///
- ///
- ///
- public static T jsonDes(string input)
+ ///
+ /// Json字符串转对象
+ ///
+ ///
+ ///
+ ///
+ public static T Str2Obj(string input)
{
- //return JsonConvert.DeserializeObject(input);
- JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
- return javaScriptSerializer.Deserialize(input);
+ return new JavaScriptSerializer().Deserialize(input);
}
- public static string json(object obj)
+
+ ///
+ /// 对象转Json字符串
+ ///
+ ///
+ ///
+ public static string Obj2Str(object obj)
{
- //return JsonConvert.SerializeObject(obj, Formatting.Indented);
- JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
- return javaScriptSerializer.Serialize(obj);
+ return new JavaScriptSerializer().Serialize(obj);
}
}
}
diff --git a/FreeControl/Utils/MoveListener.cs b/FreeControl/Utils/MoveListener.cs
index 440090f..3add81d 100644
--- a/FreeControl/Utils/MoveListener.cs
+++ b/FreeControl/Utils/MoveListener.cs
@@ -34,6 +34,10 @@ public class MoveListener
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
+
public static string GetWindowTitle(IntPtr hWnd)
{
const int nChars = 256;
@@ -50,6 +54,65 @@ private struct RECT
public int Right;
public int Bottom;
}
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
+
+ // 定义窗口状态的结构体
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ struct WINDOWPLACEMENT
+ {
+ public int length;
+ public int flags;
+ public ShowWindowCommands showCmd;
+ public POINT ptMinPosition;
+ public POINT ptMaxPosition;
+ public RECT rcNormalPosition;
+ }
+
+ // 定义显示窗口的命令
+ enum ShowWindowCommands : int
+ {
+ SW_HIDE = 0, // 隐藏窗口
+ SW_SHOWNORMAL = 1, // 正常显示窗口
+ // SW_NORMAL = 1, // 与 SW_SHOWNORMAL 相同
+ SW_SHOWMINIMIZED = 2, // 最小化窗口
+ SW_SHOWMAXIMIZED = 3, // 最大化窗口
+ // SW_MAXIMIZE = 3, // 与 SW_SHOWMAXIMIZED 相同
+ SW_SHOWNOACTIVATE = 4, // 以激活状态显示窗口,但不激活它
+ SW_SHOW = 5, // 以当前大小和位置显示窗口
+ SW_MINIMIZE = 6, // 最小化窗口
+ SW_SHOWMINNOACTIVE = 7, // 以最小化状态显示窗口,但不激活它
+ SW_SHOWNA = 8, // 在当前位置以非激活状态显示窗口
+ SW_RESTORE = 9, // 恢复窗口的大小和位置
+ SW_SHOWDEFAULT = 10, // 使用创建时的默认大小和位置显示窗口
+ SW_FORCEMINIMIZE = 11 // 最小化窗口,即使程序不响应
+ }
+
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ struct POINT
+ {
+ public int x;
+ public int y;
+ }
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ // 定义窗口位置和大小的标志
+ const uint SWP_NOSIZE = 0x0001; // 不改变窗口大小
+ const uint SWP_NOMOVE = 0x0002; // 不改变窗口位置
+ const uint SWP_NOZORDER = 0x0004; // 不改变窗口Z顺序
+ const uint SWP_NOACTIVATE = 0x0010; // 不激活窗口
+
+ // 指定置顶窗口
+ static IntPtr HWND_TOPMOST = new IntPtr(-1);
+ // 指定取消置顶窗口
+ static IntPtr HWND_NOTOPMOST = new IntPtr(-2);
#endregion
#region 钩子方式
@@ -66,6 +129,7 @@ private static void WinEventCallback(IntPtr hWinEventHook, uint eventType, IntPt
if (processId == idProcess)
{
UpdateLocation(hwnd);
+ UpdateStatus(hwnd);
}
}
}
@@ -82,21 +146,68 @@ private static void UpdateLocation(IntPtr hwnd)
Main._Setting.ScrcpyPointX = rect.Left + 8;
Main._Setting.ScrcpyPointY = rect.Top + 31;
- Main._Controller?.UpdateLocation();
+ if (Main.ControllerPtr != IntPtr.Zero)
+ {
+ // 使用winapi更新控制器位置
+ SetWindowPos(Main.ControllerPtr, IntPtr.Zero,
+ Main._Setting.ScrcpyPointX - 57, Main._Setting.ScrcpyPointY,
+ 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
lastRect = rect;
}
}
+
+ // 创建WINDOWPLACEMENT结构体
+ private static WINDOWPLACEMENT placement = new WINDOWPLACEMENT()
+ {
+ length = Marshal.SizeOf(placement)
+ };
+
+ private static void UpdateStatus(IntPtr hwnd)
+ {
+ if (hwnd == IntPtr.Zero || Main.ControllerPtr == IntPtr.Zero)
+ return;
+ if (GetWindowPlacement(hwnd, ref placement))
+ {
+
+ switch (placement.showCmd)
+ {
+ case ShowWindowCommands.SW_HIDE:
+ case ShowWindowCommands.SW_SHOWMINIMIZED:
+ case ShowWindowCommands.SW_SHOWMAXIMIZED:
+ case ShowWindowCommands.SW_SHOWMINNOACTIVE:
+ case ShowWindowCommands.SW_FORCEMINIMIZE:
+ SetWindowPos(Main.ControllerPtr, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ ShowWindow(Main.ControllerPtr, ShowWindowCommands.SW_HIDE);
+ break;
+ case ShowWindowCommands.SW_SHOWNORMAL:
+ case ShowWindowCommands.SW_SHOWNOACTIVATE:
+ case ShowWindowCommands.SW_SHOW:
+ case ShowWindowCommands.SW_SHOWNA:
+ case ShowWindowCommands.SW_RESTORE:
+ case ShowWindowCommands.SW_SHOWDEFAULT:
+ SetWindowPos(Main.ControllerPtr, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ ShowWindow(Main.ControllerPtr, ShowWindowCommands.SW_SHOWNOACTIVATE);
+ break;
+ }
+ }
+ }
#endregion
private static Timer timer;
+ private static GCHandle handle;
+
public static void StartListening(Process process, bool isHook = true)
{
if (isHook)// 使用钩子监控scrcpy窗口移动
{
+ WinEventDelegate myDelegate = WinEventCallback;
+ handle = GCHandle.Alloc(myDelegate);// 手动管理内存 避免被回收
+
idProcess = (uint)process.Id;
- hWinEventHook = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, WinEventCallback, MoveListener.idProcess, 0, WINEVENT_OUTOFCONTEXT);
+ hWinEventHook = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, (WinEventDelegate)handle.Target, MoveListener.idProcess, 0, WINEVENT_OUTOFCONTEXT);
}
else// 无线时 使用钩子无法监控到scrcpy窗口移动 暂时使用主动查询方式实现控制器吸附
{
@@ -118,6 +229,7 @@ public static void StartListening(Process process, bool isHook = true)
timer.Elapsed += (sender, e) =>
{
UpdateLocation(hwnd);
+ UpdateStatus(hwnd);
};
timer.Start();
}
@@ -134,6 +246,9 @@ public static void StopListening()
timer.Stop();
timer.Dispose();
}
+
+ if (handle.IsAllocated)
+ handle.Free();
}
}
}