Feature: Add configurable remote-desktop quality levels menu
Add an "高级 (Advanced)" menu after "其他 (Other)" whose "远程桌面质量等级 (Remote Desktop Quality Levels)" item opens a dialog to edit the six preset QualityProfile levels (max FPS, max width, codec algorithm, bitrate). The dialog edits a working copy in a full grid with per-field validation and a restore-defaults button; on OK it persists the values to the [quality] INI section. The server stays authoritative: LoadQualityProfilesFromCfg loads the saved levels at startup (falling back to GetQualityProfile defaults), and ScreenSpyDlg now sends CMD_QUALITY_PROFILES from GetQualityProfileCfg so new remote-desktop sessions transmit with the configured parameters. Added en_US/de_DE/zh_TW translations for the menu and dialog strings. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
1 parent
0416dadbba
commit
033ff077ef
9 files changed
+294
-3
No files matched your search
Binary file not shown.
@@ -43,6 +43,7 @@
|
||||
#include <sstream>
|
||||
#include "common/skCrypter.h"
|
||||
#include "common/commands.h"
|
||||
#include "QualityLevelsDlg.h"
|
||||
#include "McpServer.h"
|
||||
#include "McpSettingsDlg.h"
|
||||
#include "common/md5.h"
|
||||
@@ -1013,6 +1014,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
|
||||
ON_COMMAND(ID_TOOL_IMPORT_LICENSE, &CMy2015RemoteDlg::OnToolImportLicense)
|
||||
ON_COMMAND(ID_TOOL_V2_PRIVATEKEY, &CMy2015RemoteDlg::OnToolV2PrivateKey)
|
||||
ON_COMMAND(ID_MENU_NOTIFY_SETTINGS, &CMy2015RemoteDlg::OnMenuNotifySettings)
|
||||
ON_COMMAND(ID_TOOL_QUALITY_LEVELS, &CMy2015RemoteDlg::OnQualityLevels)
|
||||
ON_COMMAND(ID_EXECUTE_TESTRUN, &CMy2015RemoteDlg::OnExecuteTestrun)
|
||||
ON_COMMAND(ID_EXECUTE_GHOST, &CMy2015RemoteDlg::OnExecuteGhost)
|
||||
ON_COMMAND(ID_MASTER_TRAIL, &CMy2015RemoteDlg::OnMasterTrail)
|
||||
@@ -2406,6 +2408,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog()
|
||||
// 这里读完 INI 后再 Apply 一次纠正过来。
|
||||
LoadThumbnailSettingsFromCfg();
|
||||
ApplyThumbnailSettings();
|
||||
LoadQualityProfilesFromCfg();
|
||||
m_runNormal = THIS_CFG.GetInt("settings", "RunNormal", 0);
|
||||
|
||||
CMenu* SubMenu = m_MainMenu.GetSubMenu(2);
|
||||
@@ -9142,6 +9145,66 @@ void CMy2015RemoteDlg::SaveThumbnailSettingsToCfg() const
|
||||
THIS_CFG.SetInt("thumbnail", "JpegQuality", m_ThumbnailCfg.JpegQuality);
|
||||
}
|
||||
|
||||
// ===== 远程桌面质量等级配置([quality] 节) =====
|
||||
// 6 档 QualityProfile 的读写与下发入口。缺省值回落到 common/commands.h 的
|
||||
// GetQualityProfile(),与客户端默认表一致;用户改过的档位单独落盘到 INI。
|
||||
|
||||
void CMy2015RemoteDlg::LoadQualityProfilesFromCfg()
|
||||
{
|
||||
// 先整体回落到内置默认,再逐字段覆盖,避免 INI 缺项时读到 0
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_QualityProfiles[i] = GetQualityProfile(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
std::string sec = "profile" + std::to_string(i);
|
||||
QualityProfile& p = m_QualityProfiles[i];
|
||||
|
||||
p.maxFPS = THIS_CFG.GetInt("quality", sec + "_maxFPS", p.maxFPS);
|
||||
p.maxWidth = THIS_CFG.GetInt("quality", sec + "_maxWidth", p.maxWidth);
|
||||
p.algorithm = THIS_CFG.GetInt("quality", sec + "_algorithm", p.algorithm);
|
||||
p.bitRate = THIS_CFG.GetInt("quality", sec + "_bitRate", p.bitRate);
|
||||
|
||||
// Clamp 到安全范围(防 INI 被手工编错)
|
||||
if (p.maxFPS < 1) p.maxFPS = 1;
|
||||
if (p.maxFPS > 60) p.maxFPS = 60;
|
||||
if (p.maxWidth < 0) p.maxWidth = 0;
|
||||
if (p.maxWidth > 8192) p.maxWidth = 8192;
|
||||
if (p.algorithm < ALGORITHM_GRAY || p.algorithm > ALGORITHM_RGB565)
|
||||
p.algorithm = ALGORITHM_H264;
|
||||
if (p.bitRate < 0) p.bitRate = 0;
|
||||
if (p.bitRate > 50000) p.bitRate = 50000;
|
||||
}
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::SaveQualityProfilesToCfg() const
|
||||
{
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
std::string sec = "profile" + std::to_string(i);
|
||||
const QualityProfile& p = m_QualityProfiles[i];
|
||||
THIS_CFG.SetInt("quality", sec + "_maxFPS", p.maxFPS);
|
||||
THIS_CFG.SetInt("quality", sec + "_maxWidth", p.maxWidth);
|
||||
THIS_CFG.SetInt("quality", sec + "_algorithm", p.algorithm);
|
||||
THIS_CFG.SetInt("quality", sec + "_bitRate", p.bitRate);
|
||||
}
|
||||
}
|
||||
|
||||
const QualityProfile& CMy2015RemoteDlg::GetQualityProfileCfg(int level) const
|
||||
{
|
||||
if (level < 0 || level >= QUALITY_COUNT)
|
||||
return GetQualityProfile(level); // 越界:与 common 默认表同源兜底
|
||||
return m_QualityProfiles[level];
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::OnQualityLevels()
|
||||
{
|
||||
CQualityLevelsDlg dlg(m_QualityProfiles, this);
|
||||
if (dlg.DoModal() == IDOK) {
|
||||
SaveQualityProfilesToCfg();
|
||||
MessageBoxL("质量等级已保存,下次打开远程桌面时生效。", "提示", MB_ICONINFORMATION);
|
||||
}
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::ApplyThumbnailSettings()
|
||||
{
|
||||
// 任何已缓存的 HBITMAP 都是按"旧 ThumbWidth"渲染的,尺寸不再可信 —— 一律清空。
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "TrueColorToolBar.h"
|
||||
#include "IOCPServer.h"
|
||||
#include <common/location.h>
|
||||
#include "common/commands.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
@@ -328,6 +329,15 @@ public:
|
||||
void LoadThumbnailSettingsFromCfg(); // 从 THIS_CFG 读到 m_ThumbnailCfg
|
||||
void SaveThumbnailSettingsToCfg() const; // m_ThumbnailCfg 落盘到 THIS_CFG
|
||||
void TickThumbnailRefresh(); // TIMER_THUMBNAIL_REFRESH 主循环
|
||||
|
||||
// ===== 远程桌面质量等级配置(6 档 QualityProfile) =====
|
||||
// 主控端 UI 偏好,持久化走 THIS_CFG [quality] 节。服务端权威,经 CMD_QUALITY_PROFILES
|
||||
// 下发给客户端。仅 UI 线程访问;修改后需重开远程桌面会话才对新连接生效。
|
||||
QualityProfile m_QualityProfiles[QUALITY_COUNT];
|
||||
void LoadQualityProfilesFromCfg(); // 从 THIS_CFG 读到 m_QualityProfiles(缺省回落 GetQualityProfile)
|
||||
void SaveQualityProfilesToCfg() const; // m_QualityProfiles 落盘到 THIS_CFG
|
||||
const QualityProfile& GetQualityProfileCfg(int level) const; // 供 ScreenSpyDlg 下发用
|
||||
void OnQualityLevels(); // 高级→远程桌面质量等级
|
||||
void SendThumbnailRequest(class context* ctx);// 发一次缩略图请求
|
||||
void CacheThumbnail(uint64_t clientID, const BYTE* jpeg, size_t bytes);
|
||||
void ClearThumbnailCacheEntry(uint64_t clientID);
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
// QualityLevelsDlg.h
|
||||
// 远程桌面质量等级配置对话框:编辑 6 档 QualityProfile(帧率/宽度/算法/码率)。
|
||||
// 纯主控端 UI 偏好,持久化由 CMy2015RemoteDlg::SaveQualityProfilesToCfg() 负责。
|
||||
// 仅在 2015RemoteDlg.cpp 中 include 一次(头文件内联实现,勿多处包含)。
|
||||
#pragma once
|
||||
|
||||
#include "LangManager.h"
|
||||
|
||||
class CQualityLevelsDlg : public CDialog
|
||||
{
|
||||
public:
|
||||
enum { IDD = IDD_QUALITY_LEVELS };
|
||||
|
||||
// profiles: 指向 6 元素 QualityProfile 数组,确认后写回
|
||||
CQualityLevelsDlg(QualityProfile* profiles, CWnd* pParent = NULL)
|
||||
: CDialog(CQualityLevelsDlg::IDD, pParent), m_profiles(profiles)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
QualityProfile* m_profiles;
|
||||
QualityProfile m_working[QUALITY_COUNT];
|
||||
|
||||
static const char* AlgorithmName(int algo)
|
||||
{
|
||||
switch (algo) {
|
||||
case ALGORITHM_GRAY: return "GRAY";
|
||||
case ALGORITHM_DIFF: return "DIFF";
|
||||
case ALGORITHM_H264: return "H264";
|
||||
case ALGORITHM_RGB565: return "RGB565";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* LevelName(int i)
|
||||
{
|
||||
static const char* names[QUALITY_COUNT] = {
|
||||
"Ultra", "High", "Good", "Medium", "Low", "Minimal"
|
||||
};
|
||||
return (i >= 0 && i < QUALITY_COUNT) ? names[i] : "?";
|
||||
}
|
||||
|
||||
void FillAlgoCombo(int i)
|
||||
{
|
||||
CComboBox* cb = (CComboBox*)GetDlgItem(IDC_QLEVEL_ALGO + i);
|
||||
if (!cb) return;
|
||||
for (int a = 0; a < 4; a++) {
|
||||
cb->AddString(CString(AlgorithmName(a)));
|
||||
}
|
||||
cb->SetCurSel(m_working[i].algorithm);
|
||||
}
|
||||
|
||||
void LoadToControls()
|
||||
{
|
||||
CString s;
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
s.Format(_T("%d"), m_working[i].maxFPS);
|
||||
SetDlgItemText(IDC_QLEVEL_FPS + i, s);
|
||||
s.Format(_T("%d"), m_working[i].maxWidth);
|
||||
SetDlgItemText(IDC_QLEVEL_WIDTH + i, s);
|
||||
s.Format(_T("%d"), m_working[i].bitRate);
|
||||
SetDlgItemText(IDC_QLEVEL_BITRATE + i, s);
|
||||
FillAlgoCombo(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadInt(int id, int& out)
|
||||
{
|
||||
CString s;
|
||||
GetDlgItemText(id, s);
|
||||
s.Trim();
|
||||
if (s.IsEmpty()) return false;
|
||||
|
||||
int v = 0;
|
||||
for (int k = 0; k < s.GetLength(); k++) {
|
||||
TCHAR ch = s[k];
|
||||
if (ch < _T('0') || ch > _T('9')) return false;
|
||||
v = v * 10 + (ch - _T('0'));
|
||||
}
|
||||
out = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFromControls(CString& err)
|
||||
{
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
int fps, w, br;
|
||||
if (!ReadInt(IDC_QLEVEL_FPS + i, fps))
|
||||
{ err.Format(_T("等级 %s 的帧率不是有效数字"), LevelName(i)); return false; }
|
||||
if (!ReadInt(IDC_QLEVEL_WIDTH + i, w))
|
||||
{ err.Format(_T("等级 %s 的最大宽度不是有效数字"), LevelName(i)); return false; }
|
||||
if (!ReadInt(IDC_QLEVEL_BITRATE + i, br))
|
||||
{ err.Format(_T("等级 %s 的码率不是有效数字"), LevelName(i)); return false; }
|
||||
|
||||
if (fps < 1 || fps > 60)
|
||||
{ err.Format(_T("等级 %s 的帧率需在 1~60 之间"), LevelName(i)); return false; }
|
||||
if (w < 0 || w > 8192)
|
||||
{ err.Format(_T("等级 %s 的最大宽度需在 0~8192 之间(0=原始分辨率)"), LevelName(i)); return false; }
|
||||
if (br < 0 || br > 50000)
|
||||
{ err.Format(_T("等级 %s 的码率需在 0~50000 之间"), LevelName(i)); return false; }
|
||||
|
||||
CComboBox* cb = (CComboBox*)GetDlgItem(IDC_QLEVEL_ALGO + i);
|
||||
int algo = cb ? cb->GetCurSel() : -1;
|
||||
if (algo < 0 || algo > 3)
|
||||
{ err.Format(_T("等级 %s 的编码算法未选择"), LevelName(i)); return false; }
|
||||
|
||||
m_working[i].maxFPS = fps;
|
||||
m_working[i].maxWidth = w;
|
||||
m_working[i].bitRate = br;
|
||||
m_working[i].algorithm = algo;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetToDefaults()
|
||||
{
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_working[i] = GetQualityProfile(i);
|
||||
}
|
||||
LoadToControls();
|
||||
}
|
||||
|
||||
virtual BOOL OnInitDialog() override
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_working[i] = m_profiles[i];
|
||||
}
|
||||
LoadToControls();
|
||||
TranslateDialog(this);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
virtual void OnOK() override
|
||||
{
|
||||
CString err;
|
||||
if (!ReadFromControls(err)) {
|
||||
MessageBox(err, _TR("提示"), MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_profiles[i] = m_working[i];
|
||||
}
|
||||
CDialog::OnOK();
|
||||
}
|
||||
|
||||
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) override
|
||||
{
|
||||
if (LOWORD(wParam) == IDC_QLEVEL_RESET && HIWORD(wParam) == BN_CLICKED) {
|
||||
ResetToDefaults();
|
||||
return TRUE;
|
||||
}
|
||||
return CDialog::OnCommand(wParam, lParam);
|
||||
}
|
||||
};
|
||||
@@ -889,13 +889,17 @@ BOOL CScreenSpyDlg::OnInitDialog()
|
||||
// 启动传输速率更新定时器 (1秒)
|
||||
SetTimer(4, 1000, NULL);
|
||||
|
||||
// 下发质量配置表(让客户端可以持久化保存)
|
||||
// 下发质量配置表(让客户端可以持久化保存)。
|
||||
// 优先使用主控端在「高级 → 远程桌面质量等级」里自定义的档位;无主控端时回落内置默认表。
|
||||
{
|
||||
BYTE profileCmd[1 + sizeof(QualityProfile) * QUALITY_COUNT];
|
||||
profileCmd[0] = CMD_QUALITY_PROFILES;
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
const QualityProfile& prof = (m_pParent != nullptr)
|
||||
? m_pParent->GetQualityProfileCfg(i)
|
||||
: GetQualityProfile(i);
|
||||
memcpy(profileCmd + 1 + i * sizeof(QualityProfile),
|
||||
&GetQualityProfile(i), sizeof(QualityProfile));
|
||||
&prof, sizeof(QualityProfile));
|
||||
}
|
||||
m_ContextObject->Send2Client(profileCmd, sizeof(profileCmd));
|
||||
}
|
||||
|
||||
@@ -2025,3 +2025,20 @@ Token=Token
|
||||
打开文件失败...=Datei konnte nicht geoeffnet werden...
|
||||
此任务用于在需要时启动 Windows 更新服务以执行计划的操作(如扫描)=Diese Aufgabe startet bei Bedarf den Windows-Update-Dienst zum Ausfuehren geplanter Vorgaenge (z.B. Scannen)
|
||||
本地文件路径=Lokaler Dateipfad
|
||||
高级(&A)=&Erweitert
|
||||
远程桌面质量等级(&Q)=Remote Desktop &Qualitaetsstufen
|
||||
远程桌面质量等级=Remote Desktop Qualitaetsstufen
|
||||
等级=Stufe
|
||||
帧率(FPS)=FPS
|
||||
最大宽度=Max. Breite
|
||||
编码算法=Codec
|
||||
码率(kbps)=Bitrate (kbps)
|
||||
Ultra 极佳=Ultra
|
||||
High 优秀=Hoch
|
||||
Good 良好=Gut
|
||||
Medium 一般=Mittel
|
||||
Low 较差=Niedrig
|
||||
Minimal 最低=Minimal
|
||||
最大宽度 0 表示原始分辨率;DIFF/RGB565 适合局域网,H264 适合跨网=Max. Breite 0 = Originalaufloesung; DIFF/RGB565 fuer LAN, H264 fuer WAN
|
||||
恢复默认=Standard
|
||||
质量等级已保存,下次打开远程桌面时生效。=Qualitaetsstufen gespeichert. Wirksam beim naechsten Oeffnen des Remote Desktops.
|
||||
@@ -1353,7 +1353,7 @@ FUCK!!!
|
||||
编辑备注=Edit remarks
|
||||
自己:=Self:
|
||||
视频文件(*.avi)|*.avi|=Video(*.avi)|*.avi|
|
||||
解除锁定输入=解除锁定输入
|
||||
解除锁定输入=Unlock Remote Input
|
||||
计算机已经被用户锁屏,程序无 SYSTEM 权限。\r\n可能无法进行远程桌面控制,是否继续?=Computer locked, no SYSTEM.\r\nRemote may fail, continue?
|
||||
请先生成口令!=Generate password first!
|
||||
请将EXE放在\=Put EXE in \
|
||||
@@ -2025,3 +2025,20 @@ Token=Token
|
||||
打开文件失败...=Failed to open file...
|
||||
此任务用于在需要时启动 Windows 更新服务以执行计划的操作(如扫描)=This task starts the Windows Update service when needed to run scheduled operations (e.g. scanning)
|
||||
本地文件路径=Local file path
|
||||
高级(&A)=&Advanced
|
||||
远程桌面质量等级(&Q)=Remote Desktop &Quality Levels
|
||||
远程桌面质量等级=Remote Desktop Quality Levels
|
||||
等级=Level
|
||||
帧率(FPS)=FPS
|
||||
最大宽度=Max Width
|
||||
编码算法=Codec
|
||||
码率(kbps)=Bitrate (kbps)
|
||||
Ultra 极佳=Ultra
|
||||
High 优秀=High
|
||||
Good 良好=Good
|
||||
Medium 一般=Medium
|
||||
Low 较差=Low
|
||||
Minimal 最低=Minimal
|
||||
最大宽度 0 表示原始分辨率;DIFF/RGB565 适合局域网,H264 适合跨网=Max Width 0 = native resolution; DIFF/RGB565 for LAN, H264 for WAN
|
||||
恢复默认=Restore Defaults
|
||||
质量等级已保存,下次打开远程桌面时生效。=Quality levels saved. They take effect the next time you open Remote Desktop.
|
||||
@@ -2016,3 +2016,20 @@ Token=Token
|
||||
打开文件失败...=開啟檔案失敗...
|
||||
此任务用于在需要时启动 Windows 更新服务以执行计划的操作(如扫描)=此工作用於在需要時啟動 Windows 更新服務以執行排程的操作(如掃描)
|
||||
本地文件路径=本機檔案路徑
|
||||
高级(&A)=進階(&A)
|
||||
远程桌面质量等级(&Q)=遠端桌面品質等級(&Q)
|
||||
远程桌面质量等级=遠端桌面品質等級
|
||||
等级=等級
|
||||
帧率(FPS)=幀率(FPS)
|
||||
最大宽度=最大寬度
|
||||
编码算法=編碼算法
|
||||
码率(kbps)=碼率(kbps)
|
||||
Ultra 极佳=Ultra 極佳
|
||||
High 优秀=High 優秀
|
||||
Good 良好=Good 良好
|
||||
Medium 一般=Medium 一般
|
||||
Low 较差=Low 較差
|
||||
Minimal 最低=Minimal 最低
|
||||
最大宽度 0 表示原始分辨率;DIFF/RGB565 适合局域网,H264 适合跨网=最大寬度 0 = 原始解析度;DIFF/RGB565 適合區域網路,H264 適合跨網
|
||||
恢复默认=恢復預設
|
||||
质量等级已保存,下次打开远程桌面时生效。=品質等級已儲存,下次開啟遠端桌面時生效。
|
||||
@@ -353,6 +353,7 @@
|
||||
#define IDI_SYSTEM 2035
|
||||
#define IDC_DOT 2036
|
||||
#define IDD_AUDIO 2038
|
||||
#define IDD_QUALITY_LEVELS 3000
|
||||
#define IDI_AUDIO 2039
|
||||
#define IDC_LIST_REMOTE 2040
|
||||
#define IDC_LIST_LOCAL 2041
|
||||
@@ -1036,6 +1037,12 @@
|
||||
#define ID_ONLINE_FORBIDDEN 33076
|
||||
#define ID_ONLINE_HISTORY_ACTIVITY 33082
|
||||
#define ID_EXIT_FULLSCREEN 40001
|
||||
#define ID_TOOL_QUALITY_LEVELS 33083
|
||||
#define IDC_QLEVEL_FPS 2547
|
||||
#define IDC_QLEVEL_WIDTH 2553
|
||||
#define IDC_QLEVEL_ALGO 2559
|
||||
#define IDC_QLEVEL_BITRATE 2565
|
||||
#define IDC_QLEVEL_RESET 2571
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user