Feature: Add zoom functionality for remote desktop viewer in non-control mode
This commit is contained in:
@@ -505,6 +505,7 @@ BEGIN_MESSAGE_MAP(CScreenSpyDlg, CDialog)
|
||||
ON_MESSAGE(WM_RECVFILEV2_CHUNK, &CScreenSpyDlg::OnRecvFileV2Chunk)
|
||||
ON_MESSAGE(WM_RECVFILEV2_COMPLETE, &CScreenSpyDlg::OnRecvFileV2Complete)
|
||||
ON_WM_DROPFILES()
|
||||
ON_WM_CAPTURECHANGED()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
@@ -1618,9 +1619,18 @@ void CScreenSpyDlg::OnPaint()
|
||||
|
||||
int srcW = m_BitmapInfor_Full->bmiHeader.biWidth;
|
||||
int srcH = m_BitmapInfor_Full->bmiHeader.biHeight;
|
||||
if (m_bAdaptiveSize) {
|
||||
int dstW = m_CRect.Width();
|
||||
int dstH = m_CRect.Height();
|
||||
|
||||
// 放大模式渲染
|
||||
if (m_bZoomedIn && !m_rcZoomSrc.IsRectEmpty()) {
|
||||
// 使用放大区域作为源进行StretchBlt
|
||||
StretchBlt(m_hFullDC, 0, 0, dstW, dstH,
|
||||
m_hFullMemDC,
|
||||
m_rcZoomSrc.left, m_rcZoomSrc.top,
|
||||
m_rcZoomSrc.Width(), m_rcZoomSrc.Height(),
|
||||
SRCCOPY);
|
||||
} else if (m_bAdaptiveSize) {
|
||||
// 尺寸相同时用 BitBlt(更快),否则用 StretchBlt
|
||||
if (srcW == dstW && srcH == dstH) {
|
||||
BitBlt(m_hFullDC, 0, 0, srcW, srcH, m_hFullMemDC, 0, 0, SRCCOPY);
|
||||
@@ -1631,6 +1641,24 @@ void CScreenSpyDlg::OnPaint()
|
||||
BitBlt(m_hFullDC, 0, 0, srcW, srcH, m_hFullMemDC, m_ulHScrollPos, m_ulVScrollPos, SRCCOPY);
|
||||
}
|
||||
|
||||
// 绘制框选矩形
|
||||
if (m_bSelectingZoom) {
|
||||
CRect rcSelect;
|
||||
rcSelect.left = min(m_ptZoomStart.x, m_ptZoomCurrent.x);
|
||||
rcSelect.top = min(m_ptZoomStart.y, m_ptZoomCurrent.y);
|
||||
rcSelect.right = max(m_ptZoomStart.x, m_ptZoomCurrent.x);
|
||||
rcSelect.bottom = max(m_ptZoomStart.y, m_ptZoomCurrent.y);
|
||||
|
||||
// 使用虚线边框绘制选择框
|
||||
HPEN hPen = CreatePen(PS_DASH, 1, RGB(255, 0, 0));
|
||||
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);
|
||||
@@ -1813,6 +1841,10 @@ void CScreenSpyDlg::OnSysCommand(UINT nID, LPARAM lParam)
|
||||
switch (nID) {
|
||||
case IDM_CONTROL: {
|
||||
m_bIsCtrl = !m_bIsCtrl;
|
||||
// 进入控制模式时重置放大状态
|
||||
if (m_bIsCtrl && m_bZoomedIn) {
|
||||
ResetZoom();
|
||||
}
|
||||
SysMenu->CheckMenuItem(IDM_CONTROL, m_bIsCtrl ? MF_CHECKED : MF_UNCHECKED);
|
||||
SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO));
|
||||
// 控制模式:禁用本地 IME;查看模式:启用本地 IME
|
||||
@@ -2565,6 +2597,11 @@ void CScreenSpyDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
||||
|
||||
void CScreenSpyDlg::EnterFullScreen()
|
||||
{
|
||||
// 进入全屏时重置放大状态
|
||||
if (m_bZoomedIn) {
|
||||
ResetZoom();
|
||||
}
|
||||
|
||||
if (1) {
|
||||
// 1. 获取对话框当前所在的显示器
|
||||
HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
@@ -2652,6 +2689,11 @@ void CScreenSpyDlg::EnterFullScreen()
|
||||
// 全屏退出成功则返回true
|
||||
bool CScreenSpyDlg::LeaveFullScreen()
|
||||
{
|
||||
// 退出全屏时重置放大状态
|
||||
if (m_bZoomedIn) {
|
||||
ResetZoom();
|
||||
}
|
||||
|
||||
if (1) {
|
||||
KillTimer(1);
|
||||
if (m_pToolbar) {
|
||||
@@ -2692,14 +2734,165 @@ bool CScreenSpyDlg::LeaveFullScreen()
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 局部放大功能辅助函数 ==========
|
||||
|
||||
// 重置放大状态
|
||||
void CScreenSpyDlg::ResetZoom()
|
||||
{
|
||||
m_bZoomedIn = false;
|
||||
m_bSelectingZoom = false;
|
||||
m_bZoomDragging = false;
|
||||
m_rcZoomSrc.SetRectEmpty();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// 屏幕坐标转原图坐标(考虑放大状态)
|
||||
CPoint CScreenSpyDlg::ScreenToImage(CPoint pt)
|
||||
{
|
||||
if (!m_BitmapInfor_Full) return pt;
|
||||
|
||||
int dstW = m_CRect.Width();
|
||||
int dstH = m_CRect.Height();
|
||||
if (dstW <= 0 || dstH <= 0) return pt; // 防止除零
|
||||
|
||||
if (m_bZoomedIn && !m_rcZoomSrc.IsRectEmpty()) {
|
||||
// 放大状态:从显示区域映射到放大区域
|
||||
double scaleX = (double)m_rcZoomSrc.Width() / dstW;
|
||||
double scaleY = (double)m_rcZoomSrc.Height() / dstH;
|
||||
return CPoint(
|
||||
(int)(m_rcZoomSrc.left + pt.x * scaleX),
|
||||
(int)(m_rcZoomSrc.top + pt.y * scaleY)
|
||||
);
|
||||
} else if (m_bAdaptiveSize) {
|
||||
// 自适应模式:按比例缩放
|
||||
return CPoint((int)(pt.x * m_wZoom), (int)(pt.y * m_hZoom));
|
||||
} else {
|
||||
// 滚动模式:加上滚动偏移
|
||||
return CPoint(pt.x + m_ulHScrollPos, pt.y + m_ulVScrollPos);
|
||||
}
|
||||
}
|
||||
|
||||
// 原图坐标转屏幕坐标(考虑放大状态)
|
||||
CPoint CScreenSpyDlg::ImageToScreen(CPoint pt)
|
||||
{
|
||||
if (!m_BitmapInfor_Full) return pt;
|
||||
|
||||
int zoomW = m_rcZoomSrc.Width();
|
||||
int zoomH = m_rcZoomSrc.Height();
|
||||
|
||||
if (m_bZoomedIn && zoomW > 0 && zoomH > 0) {
|
||||
// 放大状态:从放大区域映射到显示区域
|
||||
int dstW = m_CRect.Width();
|
||||
int dstH = m_CRect.Height();
|
||||
double scaleX = (double)dstW / zoomW;
|
||||
double scaleY = (double)dstH / zoomH;
|
||||
return CPoint(
|
||||
(int)((pt.x - m_rcZoomSrc.left) * scaleX),
|
||||
(int)((pt.y - m_rcZoomSrc.top) * scaleY)
|
||||
);
|
||||
} else if (m_bAdaptiveSize) {
|
||||
if (m_wZoom > 0 && m_hZoom > 0) {
|
||||
return CPoint((int)(pt.x / m_wZoom), (int)(pt.y / m_hZoom));
|
||||
}
|
||||
return pt;
|
||||
} else {
|
||||
return CPoint(pt.x - m_ulHScrollPos, pt.y - m_ulVScrollPos);
|
||||
}
|
||||
}
|
||||
|
||||
void CScreenSpyDlg::OnLButtonDown(UINT nFlags, CPoint point)
|
||||
{
|
||||
// 非控制模式下的放大功能
|
||||
if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) {
|
||||
if (m_bZoomedIn) {
|
||||
// 放大状态:开始拖拽平移
|
||||
m_bZoomDragging = true;
|
||||
m_ptZoomDragStart = point; // 保存起点用于点击检测
|
||||
m_ptZoomDragLast = point; // 用于增量拖拽计算
|
||||
SetCapture();
|
||||
return;
|
||||
} else {
|
||||
// 正常状态:开始框选放大区域
|
||||
m_bSelectingZoom = true;
|
||||
m_ptZoomStart = point;
|
||||
m_ptZoomCurrent = point;
|
||||
SetCapture();
|
||||
return;
|
||||
}
|
||||
}
|
||||
__super::OnLButtonDown(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
void CScreenSpyDlg::OnLButtonUp(UINT nFlags, CPoint point)
|
||||
{
|
||||
// 处理放大功能的鼠标释放
|
||||
if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) {
|
||||
if (m_bSelectingZoom) {
|
||||
// 完成框选
|
||||
ReleaseCapture();
|
||||
m_bSelectingZoom = false;
|
||||
|
||||
// 计算选择区域(确保left<right, top<bottom)
|
||||
CRect rcSelect;
|
||||
rcSelect.left = min(m_ptZoomStart.x, point.x);
|
||||
rcSelect.top = min(m_ptZoomStart.y, point.y);
|
||||
rcSelect.right = max(m_ptZoomStart.x, point.x);
|
||||
rcSelect.bottom = max(m_ptZoomStart.y, point.y);
|
||||
|
||||
// 框选区域太小时视为点击,如果已放大则还原
|
||||
if (rcSelect.Width() < 20 || rcSelect.Height() < 20) {
|
||||
if (m_bZoomedIn) {
|
||||
ResetZoom();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 将屏幕坐标转换为原图坐标
|
||||
int srcW = m_BitmapInfor_Full->bmiHeader.biWidth;
|
||||
int srcH = m_BitmapInfor_Full->bmiHeader.biHeight;
|
||||
int dstW = m_CRect.Width();
|
||||
int dstH = m_CRect.Height();
|
||||
|
||||
if (m_bAdaptiveSize) {
|
||||
m_rcZoomSrc.left = (int)(rcSelect.left * m_wZoom);
|
||||
m_rcZoomSrc.top = (int)(rcSelect.top * m_hZoom);
|
||||
m_rcZoomSrc.right = (int)(rcSelect.right * m_wZoom);
|
||||
m_rcZoomSrc.bottom = (int)(rcSelect.bottom * m_hZoom);
|
||||
} else {
|
||||
m_rcZoomSrc.left = rcSelect.left + m_ulHScrollPos;
|
||||
m_rcZoomSrc.top = rcSelect.top + m_ulVScrollPos;
|
||||
m_rcZoomSrc.right = rcSelect.right + m_ulHScrollPos;
|
||||
m_rcZoomSrc.bottom = rcSelect.bottom + m_ulVScrollPos;
|
||||
}
|
||||
|
||||
// 限制在原图范围内
|
||||
m_rcZoomSrc.left = max(0L, min(m_rcZoomSrc.left, (LONG)srcW));
|
||||
m_rcZoomSrc.top = max(0L, min(m_rcZoomSrc.top, (LONG)srcH));
|
||||
m_rcZoomSrc.right = max(0L, min(m_rcZoomSrc.right, (LONG)srcW));
|
||||
m_rcZoomSrc.bottom = max(0L, min(m_rcZoomSrc.bottom, (LONG)srcH));
|
||||
|
||||
// 进入放大状态
|
||||
m_bZoomedIn = true;
|
||||
Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bZoomDragging) {
|
||||
// 完成拖拽
|
||||
ReleaseCapture();
|
||||
m_bZoomDragging = false;
|
||||
|
||||
// 检查是否为点击(几乎没有移动)
|
||||
int dx = abs(point.x - m_ptZoomDragStart.x);
|
||||
int dy = abs(point.y - m_ptZoomDragStart.y);
|
||||
if (dx < 5 && dy < 5) {
|
||||
// 点击还原
|
||||
ResetZoom();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
__super::OnLButtonUp(nFlags, point);
|
||||
}
|
||||
|
||||
@@ -2725,6 +2918,66 @@ BOOL CScreenSpyDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
|
||||
|
||||
void CScreenSpyDlg::OnMouseMove(UINT nFlags, CPoint point)
|
||||
{
|
||||
// 处理放大功能的鼠标移动
|
||||
if (!m_bIsCtrl && !m_bIsFirst && m_BitmapInfor_Full) {
|
||||
if (m_bSelectingZoom) {
|
||||
// 框选中:更新当前点并重绘选择框
|
||||
m_ptZoomCurrent = point;
|
||||
Invalidate(FALSE); // FALSE表示不擦除背景,减少闪烁
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bZoomDragging) {
|
||||
// 拖拽平移:计算偏移量并移动放大区域
|
||||
int dx = point.x - m_ptZoomDragLast.x;
|
||||
int dy = point.y - m_ptZoomDragLast.y;
|
||||
m_ptZoomDragLast = point; // 更新上一点(保持m_ptZoomDragStart不变用于点击检测)
|
||||
|
||||
// 计算缩放比例(添加除零保护)
|
||||
int srcW = m_BitmapInfor_Full->bmiHeader.biWidth;
|
||||
int srcH = m_BitmapInfor_Full->bmiHeader.biHeight;
|
||||
int dstW = m_CRect.Width();
|
||||
int dstH = m_CRect.Height();
|
||||
int zoomW = m_rcZoomSrc.Width();
|
||||
int zoomH = m_rcZoomSrc.Height();
|
||||
|
||||
if (dstW <= 0 || dstH <= 0 || zoomW <= 0 || zoomH <= 0) {
|
||||
return; // 防止除零
|
||||
}
|
||||
|
||||
double scaleX = (double)zoomW / dstW;
|
||||
double scaleY = (double)zoomH / dstH;
|
||||
|
||||
// 将屏幕偏移转换为原图偏移(方向相反)
|
||||
int imgDx = (int)(-dx * scaleX);
|
||||
int imgDy = (int)(-dy * scaleY);
|
||||
|
||||
// 移动放大区域
|
||||
m_rcZoomSrc.OffsetRect(imgDx, imgDy);
|
||||
|
||||
// 限制在原图范围内
|
||||
if (m_rcZoomSrc.left < 0) {
|
||||
m_rcZoomSrc.right -= m_rcZoomSrc.left;
|
||||
m_rcZoomSrc.left = 0;
|
||||
}
|
||||
if (m_rcZoomSrc.top < 0) {
|
||||
m_rcZoomSrc.bottom -= m_rcZoomSrc.top;
|
||||
m_rcZoomSrc.top = 0;
|
||||
}
|
||||
if (m_rcZoomSrc.right > srcW) {
|
||||
m_rcZoomSrc.left -= (m_rcZoomSrc.right - srcW);
|
||||
m_rcZoomSrc.right = srcW;
|
||||
}
|
||||
if (m_rcZoomSrc.bottom > srcH) {
|
||||
m_rcZoomSrc.top -= (m_rcZoomSrc.bottom - srcH);
|
||||
m_rcZoomSrc.bottom = srcH;
|
||||
}
|
||||
|
||||
Invalidate(FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Settings.RemoteCursor) {
|
||||
if (m_pToolbar != NULL && ::IsWindow(m_pToolbar->m_hWnd) && m_pToolbar->IsWindowVisible()) {
|
||||
CRect rcToolbar;
|
||||
@@ -2807,11 +3060,26 @@ void CScreenSpyDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
|
||||
void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl)
|
||||
{
|
||||
m_bIsCtrl = ctrl;
|
||||
// 进入控制模式时重置放大状态
|
||||
if (m_bIsCtrl && m_bZoomedIn) {
|
||||
ResetZoom();
|
||||
}
|
||||
SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO));
|
||||
// 控制模式:禁用本地 IME;查看模式:启用本地 IME
|
||||
ImmAssociateContext(m_hWnd, m_bIsCtrl ? NULL : m_hOldIMC);
|
||||
}
|
||||
|
||||
void CScreenSpyDlg::OnCaptureChanged(CWnd* pWnd)
|
||||
{
|
||||
// 捕获丢失时重置框选/拖拽状态
|
||||
if (m_bSelectingZoom || m_bZoomDragging) {
|
||||
m_bSelectingZoom = false;
|
||||
m_bZoomDragging = false;
|
||||
Invalidate();
|
||||
}
|
||||
__super::OnCaptureChanged(pWnd);
|
||||
}
|
||||
|
||||
void CScreenSpyDlg::OnDropFiles(HDROP hDropInfo)
|
||||
{
|
||||
if (m_bIsCtrl && m_bConnected) {
|
||||
|
||||
@@ -223,6 +223,20 @@ public:
|
||||
double m_wZoom=1, m_hZoom=1;
|
||||
bool m_bMouseTracking = false;
|
||||
|
||||
// ========== 局部放大功能 ==========
|
||||
bool m_bZoomedIn = false; // 是否处于放大状态
|
||||
CRect m_rcZoomSrc; // 放大区域(原图坐标)
|
||||
bool m_bSelectingZoom = false; // 是否正在框选
|
||||
CPoint m_ptZoomStart; // 框选起点(屏幕坐标)
|
||||
CPoint m_ptZoomCurrent; // 框选当前点(屏幕坐标)
|
||||
bool m_bZoomDragging = false; // 是否正在拖拽平移
|
||||
CPoint m_ptZoomDragStart; // 拖拽起点(用于点击检测)
|
||||
CPoint m_ptZoomDragLast; // 拖拽上一点(用于增量计算)
|
||||
|
||||
void ResetZoom(); // 重置放大状态
|
||||
CPoint ScreenToImage(CPoint pt); // 屏幕坐标转原图坐标
|
||||
CPoint ImageToScreen(CPoint pt); // 原图坐标转屏幕坐标
|
||||
|
||||
CString m_aviFile;
|
||||
CBmpToAvi m_aviStream;
|
||||
|
||||
@@ -302,6 +316,7 @@ public:
|
||||
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
|
||||
afx_msg void OnMouseLeave();
|
||||
afx_msg void OnKillFocus(CWnd* pNewWnd);
|
||||
afx_msg void OnCaptureChanged(CWnd* pWnd);
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
|
||||
afx_msg LRESULT OnDisconnect(WPARAM wParam, LPARAM lParam);
|
||||
|
||||
Reference in New Issue
Block a user