mirror of
https://github.com/yuanyuanxiang/SimpleRemoter.git
synced 2026-01-21 15:03:09 +08:00
Feature: Support using remote cursor in screen control
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user