From eaa0cc6d0bd4466eee84cd04812709af384c126c Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Sun, 14 Jun 2026 01:02:53 +0200 Subject: [PATCH] Feat: Z button ROI region, sends COMMAND_SCREEN_ROI to restrict capture area --- client/IOCPClient.cpp | 6 +- server/2015Remote/2015RemoteDlg.cpp | 12 ++-- server/2015Remote/2015RemoteDlg.h | 1 + server/2015Remote/CIconButton.cpp | 5 +- server/2015Remote/CIconButton.h | 2 + server/2015Remote/ScreenSpyDlg.cpp | 94 +++++++++++++++++++++++++++-- server/2015Remote/ScreenSpyDlg.h | 9 +++ server/2015Remote/ToolbarDlg.cpp | 20 +++++- server/2015Remote/lang/en_US.ini | 5 +- server/2015Remote/lang/zh_TW.ini | 5 +- 10 files changed, 142 insertions(+), 17 deletions(-) diff --git a/client/IOCPClient.cpp b/client/IOCPClient.cpp index 59952d4..525a262 100644 --- a/client/IOCPClient.cpp +++ b/client/IOCPClient.cpp @@ -619,12 +619,12 @@ VOID IOCPClient::OnServerReceiving(CBuffer* m_CompressedBuffer, char* szBuffer, FlagType flagType = CheckHead(szPacketFlag, encType); if (flagType == FLAG_UNKNOWN) { // 打印诊断信息 + std::string buf; ULONG bufLen = m_CompressedBuffer->GetBufferLength(); - Mprintf("[ERROR] Unknown header! bufLen=%lu, first 16 bytes: ", bufLen); for (int i = 0; i < 16 && i < (int)bufLen; ++i) { - Mprintf("%02X ", (unsigned char)src[i]); + char tmp[12]; sprintf(tmp, "%02X ", (unsigned char)src[i]); buf += tmp; } - Mprintf("\n"); + Mprintf("[ERROR] Unknown header! bufLen=%lu, first 16 bytes: %s\n", bufLen, buf.c_str()); m_CompressedBuffer->ClearBuffer(); break; } diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 57292c7..7bdd7d1 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -1983,10 +1983,14 @@ BOOL CMy2015RemoteDlg::OnInitDialog() Mprintf("[WebService] Admin password configured from %s\n", (webPassEnv && *webPassEnv) ? BRAND_WEB_ENV_VAR : BRAND_ENV_VAR); } else { - WebService().SetAdminPassword("admin"); - Mprintf("[WebService] Warning: neither %s nor %s set! Use 'admin' as password\n", - BRAND_WEB_ENV_VAR, BRAND_ENV_VAR); + char random[12]; + sprintf(random, "%04d", (int)(time(0) % 9999)); + webPass = std::string("admin") + random; + WebService().SetAdminPassword(webPass); + Mprintf("[WebService] Warning: neither %s nor %s set! Use '%s' as password\n", + BRAND_WEB_ENV_VAR, BRAND_ENV_VAR, webPass.c_str()); } + m_webPass = webPass; // HideWebSessions: 1=hide (default), 0=show (for debugging) WebService().SetHideWebSessions(THIS_CFG.GetInt("settings", "HideWebSessions", 1) != 0); if (!WebService().Start(webSvrPort)) { @@ -11043,7 +11047,7 @@ void CMy2015RemoteDlg::OnWebRemoteControl() return; } else if (m_superPass.empty()) { - MessageBoxL(_L("请设置环境变量 " BRAND_WEB_ENV_VAR " 来使用Web远程桌面!") + _L("\n默认密码是: admin") + MessageBoxL(_L("请设置环境变量 " BRAND_WEB_ENV_VAR " 来使用Web远程桌面!") + _L("\n当前密码是: ") + m_webPass.c_str() , "提示", MB_ICONINFORMATION); }else { MessageBoxL("如需Web远程桌面跨网使用方案,请联系管理员!", "提示", MB_ICONINFORMATION); diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 6cbc0e5..4590bc8 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -156,6 +156,7 @@ protected: HICON m_hIcon; void* m_tinyDLL; std::string m_superPass; + std::string m_webPass; BOOL m_needNotify = FALSE; DWORD g_StartTick; BOOL m_bHookWIN = TRUE; diff --git a/server/2015Remote/CIconButton.cpp b/server/2015Remote/CIconButton.cpp index 55db529..ec28ed9 100644 --- a/server/2015Remote/CIconButton.cpp +++ b/server/2015Remote/CIconButton.cpp @@ -21,6 +21,7 @@ CIconButton::CIconButton() , m_bHover(false) , m_bIsCloseButton(false) , m_bTracking(false) + , m_bActive(false) { } @@ -42,10 +43,10 @@ void CIconButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) bool bPressed = (lpDIS->itemState & ODS_SELECTED) != 0; // Pick background color - COLORREF clrBg = CLR_NORMAL; + COLORREF clrBg = m_bActive ? RGB(0, 100, 200) : CLR_NORMAL; if (bPressed) { clrBg = CLR_PRESSED; - } else if (m_bHover) { + } else if (!m_bActive && m_bHover) { clrBg = m_bIsCloseButton ? CLR_CLOSE_HOVER : CLR_HOVER; } diff --git a/server/2015Remote/CIconButton.h b/server/2015Remote/CIconButton.h index 358b3c3..67f5b13 100644 --- a/server/2015Remote/CIconButton.h +++ b/server/2015Remote/CIconButton.h @@ -18,6 +18,7 @@ public: void SetIconDrawFunc(IconDrawFunc fn) { m_fnDrawIcon = fn; } void SetIsCloseButton(bool b) { m_bIsCloseButton = b; } + void SetActive(bool b) { m_bActive = b; Invalidate(FALSE); } // --- Static icon draw functions --- static void DrawIconExitFullscreen(CDC* pDC, const CRect& rc); @@ -63,4 +64,5 @@ private: bool m_bHover; bool m_bIsCloseButton; bool m_bTracking; + bool m_bActive; }; diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 6d444ba..ef7bb8f 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -1730,7 +1730,7 @@ void CScreenSpyDlg::OnPaint() } } - // 绘制框选矩形(左键放大用红色,右键截图用绿色,二者颜色错开避免误操作) + // 绘制框选矩形(左键放大用红色,右键截图用绿色,ROI用蓝色) if (m_bSelectingZoom || m_bSelectingShot) { CPoint ptStart = m_bSelectingZoom ? m_ptZoomStart : m_ptShotStart; CPoint ptCur = m_bSelectingZoom ? m_ptZoomCurrent : m_ptShotCurrent; @@ -1751,6 +1751,21 @@ void CScreenSpyDlg::OnPaint() DeleteObject(hPen); } + if (m_bSelectingROI) { + CRect rcSelect; + rcSelect.left = min(m_ptROIStart.x, m_ptROICurrent.x); + rcSelect.top = min(m_ptROIStart.y, m_ptROICurrent.y); + rcSelect.right = max(m_ptROIStart.x, m_ptROICurrent.x); + rcSelect.bottom = max(m_ptROIStart.y, m_ptROICurrent.y); + HPEN hPen = CreatePen(PS_DASH, 1, RGB(0, 120, 215)); + HPEN hOldPen = (HPEN)SelectObject(m_hFullDC, hPen); + HBRUSH hOldBrush = (HBRUSH)SelectObject(m_hFullDC, GetStockObject(NULL_BRUSH)); + Rectangle(m_hFullDC, rcSelect.left, rcSelect.top, rcSelect.right, rcSelect.bottom); + SelectObject(m_hFullDC, hOldBrush); + SelectObject(m_hFullDC, hOldPen); + DeleteObject(hPen); + } + if ((m_bIsCtrl && m_Settings.RemoteCursor) || m_bIsTraceCursor) { CPoint ptLocal; GetCursorPos(&ptLocal); @@ -2880,6 +2895,30 @@ void CScreenSpyDlg::ResetZoom() Invalidate(); } +void CScreenSpyDlg::SendROICommand(const RECT& rc) +{ + if (!m_bConnected) return; + BYTE buf[1 + sizeof(RECT)]; + buf[0] = COMMAND_SCREEN_ROI; + memcpy(buf + 1, &rc, sizeof(RECT)); + m_ContextObject->Send2Client(buf, sizeof(buf)); +} + +void CScreenSpyDlg::ResetROI() +{ + bool wasActive = m_bROIActive; + m_bROIArmed = false; + m_bROIActive = false; + m_bSelectingROI = false; + if (GetCapture() == this) ReleaseCapture(); + if (wasActive) { // ROI 未曾激活则不通知远程,避免不必要的 RestartScreen + RECT rc = {0}; + SendROICommand(rc); + } + if (m_pToolbar) m_pToolbar->UpdateButtonIcons(); + Invalidate(); +} + // 屏幕坐标转原图坐标(考虑放大状态) CPoint CScreenSpyDlg::ScreenToImage(CPoint pt) { @@ -2938,6 +2977,15 @@ void CScreenSpyDlg::OnLButtonDown(UINT nFlags, CPoint point) { // 非控制模式下的放大功能 if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) { + if (m_bROIArmed) { + // ROI 待选状态:开始拖选 ROI 区域 + m_bROIArmed = false; + m_bSelectingROI = true; + m_ptROIStart = point; + m_ptROICurrent = point; + SetCapture(); + return; + } if (m_bZoomedIn) { // 放大状态:开始拖拽平移 m_bZoomDragging = true; @@ -2962,6 +3010,28 @@ void CScreenSpyDlg::OnLButtonUp(UINT nFlags, CPoint point) { // 处理放大功能的鼠标释放 if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) { + if (m_bSelectingROI) { + ReleaseCapture(); + m_bSelectingROI = false; + CRect rcSelect; + rcSelect.left = min(m_ptROIStart.x, point.x); + rcSelect.top = min(m_ptROIStart.y, point.y); + rcSelect.right = max(m_ptROIStart.x, point.x); + rcSelect.bottom = max(m_ptROIStart.y, point.y); + if (rcSelect.Width() < 20 || rcSelect.Height() < 20) { + m_bROIArmed = true; // 框选太小,重新进入待选状态 + return; + } + CRect rcImage; + if (ScreenRectToImageRect(rcSelect, rcImage)) { + RECT rc = { rcImage.left, rcImage.top, rcImage.right, rcImage.bottom }; + SendROICommand(rc); + m_bROIActive = true; + } + if (m_pToolbar) m_pToolbar->UpdateButtonIcons(); + return; + } + if (m_bSelectingZoom) { // 完成框选 ReleaseCapture(); @@ -3017,7 +3087,7 @@ void CScreenSpyDlg::OnRButtonDown(UINT nFlags, CPoint point) // 非控制模式下:右键框选 → 截图保存。控制模式下右键由 PreTranslateMessage 转发给客户端。 if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) { // 与左键互斥:左键正在框选/拖拽时不接管右键,避免冲突 - if (m_bSelectingZoom || m_bZoomDragging) { + if (m_bSelectingZoom || m_bZoomDragging || m_bROIArmed || m_bSelectingROI) { return; } m_bSelectingShot = true; @@ -3174,6 +3244,11 @@ void CScreenSpyDlg::OnMouseMove(UINT nFlags, CPoint point) { // 处理放大功能的鼠标移动 if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) { + if (m_bSelectingROI) { + m_ptROICurrent = point; + Invalidate(FALSE); + return; + } if (m_bSelectingZoom) { // 框选中:更新当前点并重绘选择框 m_ptZoomCurrent = point; @@ -3320,7 +3395,7 @@ void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl) { m_bIsCtrl = ctrl; m_bIsTraceCursor = !m_bIsCtrl; - // 进入控制模式时重置放大状态 + 中止任何正在进行的右键截图框选 + // 进入控制模式时重置放大状态 + 中止任何正在进行的右键截图/ROI框选 if (m_bIsCtrl) { if (m_bZoomedIn) ResetZoom(); if (m_bSelectingShot) { @@ -3328,6 +3403,13 @@ void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl) if (GetCapture() == this) ReleaseCapture(); Invalidate(FALSE); } + if (m_bROIArmed || m_bSelectingROI) { + m_bROIArmed = false; + m_bSelectingROI = false; + if (GetCapture() == this) ReleaseCapture(); + if (m_pToolbar) m_pToolbar->UpdateButtonIcons(); + Invalidate(FALSE); + } } SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO)); // 控制模式:禁用本地 IME;查看模式:启用本地 IME @@ -3342,10 +3424,14 @@ void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl) void CScreenSpyDlg::OnCaptureChanged(CWnd* pWnd) { // 捕获丢失时重置框选/拖拽状态 - if (m_bSelectingZoom || m_bZoomDragging || m_bSelectingShot) { + if (m_bSelectingZoom || m_bZoomDragging || m_bSelectingShot || m_bSelectingROI) { m_bSelectingZoom = false; m_bZoomDragging = false; m_bSelectingShot = false; + if (m_bSelectingROI) { + m_bSelectingROI = false; + m_bROIArmed = true; // 保留待选状态,让用户可以重试 + } Invalidate(); } __super::OnCaptureChanged(pWnd); diff --git a/server/2015Remote/ScreenSpyDlg.h b/server/2015Remote/ScreenSpyDlg.h index 91062d8..96638a1 100644 --- a/server/2015Remote/ScreenSpyDlg.h +++ b/server/2015Remote/ScreenSpyDlg.h @@ -297,6 +297,15 @@ public: CPoint m_ptShotStart; // 右键框选起点(屏幕坐标) CPoint m_ptShotCurrent; // 右键框选当前点(屏幕坐标) + // ========== 远程ROI功能(Z按钮) ========== + bool m_bROIArmed = false; // Z已点击,等待拖选 + bool m_bROIActive = false; // ROI已发送到远程,Z高亮 + bool m_bSelectingROI = false; // 正在拖选ROI区域 + CPoint m_ptROIStart; // 拖选起点(屏幕坐标) + CPoint m_ptROICurrent; // 拖选当前点(屏幕坐标) + void SendROICommand(const RECT& rc); // 发送COMMAND_SCREEN_ROI(不依赖控制模式) + void ResetROI(); // 清除ROI并通知远程 + void ResetZoom(); // 重置放大状态 CPoint ScreenToImage(CPoint pt); // 屏幕坐标转原图坐标 CPoint ImageToScreen(CPoint pt); // 原图坐标转屏幕坐标 diff --git a/server/2015Remote/ToolbarDlg.cpp b/server/2015Remote/ToolbarDlg.cpp index b1cb340..329301d 100644 --- a/server/2015Remote/ToolbarDlg.cpp +++ b/server/2015Remote/ToolbarDlg.cpp @@ -365,7 +365,7 @@ BOOL CToolbarDlg::OnInitDialog() m_tooltip.AddTool(&m_btnRestoreConsole, _TR("RDP会话归位")); m_tooltip.AddTool(&m_btnX, _TR("切换窗口")); // 类似 Alt+Tab m_tooltip.AddTool(&m_btnY, pParent->m_Settings.AudioEnabled ? _TR("关闭系统音频") : _TR("打开系统音频")); - m_tooltip.AddTool(&m_btnZ, _T("Z")); // 预留按钮 + m_tooltip.AddTool(&m_btnZ, _TR("选择ROI")); m_tooltip.AddTool(&m_btnScreenshot, _TR("截图")); m_tooltip.AddTool(&m_btnMinimize, _TR("最小化")); m_tooltip.AddTool(&m_btnClose, _TR("关闭")); @@ -502,6 +502,12 @@ void CToolbarDlg::UpdateButtonIcons() m_tooltip.UpdateTipText(_TR("打开系统音频"), &m_btnY); } m_btnY.Invalidate(FALSE); + + // Z button (ROI) + bool roiOn = pParent->m_bROIActive || pParent->m_bROIArmed; + m_btnZ.SetActive(roiOn); + m_tooltip.UpdateTipText(roiOn ? _TR("取消ROI") : _TR("选择ROI"), &m_btnZ); + m_btnZ.Invalidate(FALSE); } void CToolbarDlg::LayoutButtons() @@ -758,7 +764,17 @@ void CToolbarDlg::OnBnClickedY() void CToolbarDlg::OnBnClickedZ() { - // TODO: 预留按钮 Z 的响应函数 + CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent(); + if (!pParent || !pParent->m_ContextObject) return; + if (pParent->m_bROIActive || pParent->m_bROIArmed || pParent->m_bSelectingROI) { + pParent->ResetROI(); + } else { + if (pParent->m_bIsCtrl) + pParent->UpdateCtrlStatus(FALSE); // 先退出控制模式再进入ROI选择 + pParent->m_bROIArmed = true; + if (pParent->m_bZoomedIn) pParent->ResetZoom(); + UpdateButtonIcons(); + } } void CToolbarDlg::OnBnClickedScreenshot() diff --git a/server/2015Remote/lang/en_US.ini b/server/2015Remote/lang/en_US.ini index ace7740..0948c24 100644 --- a/server/2015Remote/lang/en_US.ini +++ b/server/2015Remote/lang/en_US.ini @@ -1750,6 +1750,8 @@ Ghostִ ־=Clear Log ־=Hide Message Ϣ=Copy Information +ѡROI=Select ROI +ȡROI=Exit Selecting FRPS ڱ=FRPS runs on localhost ַ:=LAN Address: õַΪFRPIP=Address must be FRP proxy server IP @@ -1927,6 +1929,7 @@ FRPC Զ =Error ѹ(&C)=&Compress ѹ(&U)=&Uncompress -\nĬ: admin=\nDefault password is: admin +\nǰ: =\nDefault password is: ж=Uninstall Software ǷƳ=Uninstall this software. Are you sure? +[ȫʾ] Web!!!=[Security Warning] Please set web password!!! diff --git a/server/2015Remote/lang/zh_TW.ini b/server/2015Remote/lang/zh_TW.ini index 0c350f6..4757fdf 100644 --- a/server/2015Remote/lang/zh_TW.ini +++ b/server/2015Remote/lang/zh_TW.ini @@ -1743,6 +1743,8 @@ Ghostִ ־=I ־=I Ϣ=Ϣ +ѡROI=xROI +ȡROI=ȡROI FRPS ڱ=FRPS ڱ ַ:=ھWַ: õַΪFRPIP=ԓַ횞FRPIP @@ -1918,6 +1920,7 @@ FRPC Զ =e` ѹ(&C)=s(&C) ѹ(&U)=≺s(&U) -\nĬ: admin=\nĬ: admin +\nǰ: =\nĬ: ж=ж ǷƳ=ǷƳ +[ȫʾ] Web!!!=[ȫʾ] Web!!!