diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 675488a..2d1cb16 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -494,6 +494,8 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_EXECUTE_DOWNLOAD, &CMy2015RemoteDlg::OnExecuteDownload) ON_COMMAND(ID_EXECUTE_UPLOAD, &CMy2015RemoteDlg::OnExecuteUpload) ON_COMMAND(ID_MACHINE_LOGOUT, &CMy2015RemoteDlg::OnMachineLogout) + ON_WM_DESTROY() + ON_MESSAGE(WM_SESSION_ACTIVATED, &CMy2015RemoteDlg::OnSessionActivatedMsg) END_MESSAGE_MAP() @@ -962,6 +964,9 @@ BOOL CMy2015RemoteDlg::OnInitDialog() { AUTO_TICK(500); CDialogEx::OnInitDialog(); + + g_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, AfxGetInstanceHandle(), 0); + m_GroupList = {"default"}; // Grid 容器 int size = THIS_CFG.GetInt("settings", "VideoWallSize"); @@ -3428,3 +3433,142 @@ void CMy2015RemoteDlg::OnExecuteUpload() { TODO_NOTICE; } + + +void CMy2015RemoteDlg::OnDestroy() +{ + if (g_hKeyboardHook) + { + UnhookWindowsHookEx(g_hKeyboardHook); + g_hKeyboardHook = NULL; + } + CDialogEx::OnDestroy(); +} + +CString GetClipboardText() +{ + if (!OpenClipboard(nullptr)) return _T(""); + +#ifdef UNICODE + HANDLE hData = GetClipboardData(CF_UNICODETEXT); +#else + HANDLE hData = GetClipboardData(CF_TEXT); +#endif + + if (!hData) { CloseClipboard(); return _T(""); } + +#ifdef UNICODE + wchar_t* pszText = static_cast(GlobalLock(hData)); +#else + char* pszText = static_cast(GlobalLock(hData)); +#endif + + CString strText = pszText ? pszText : _T(""); + GlobalUnlock(hData); + CloseClipboard(); + return strText; +} + +void SetClipboardText(const CString& text) +{ + if (!OpenClipboard(nullptr)) return; + EmptyClipboard(); + +#ifdef UNICODE + HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, (text.GetLength() + 1) * sizeof(wchar_t)); + wchar_t* p = static_cast(GlobalLock(hGlob)); + if (p) wcscpy_s(p, text.GetLength() + 1, text); +#else + HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, (text.GetLength() + 1) * sizeof(char)); + char* p = static_cast(GlobalLock(hGlob)); + if (p) strcpy_s(p, text.GetLength() + 1, CT2A(text)); // CT2A 宏把 CString 转成 char* +#endif + + GlobalUnlock(hGlob); +#ifdef UNICODE + SetClipboardData(CF_UNICODETEXT, hGlob); +#else + SetClipboardData(CF_TEXT, hGlob); +#endif + CloseClipboard(); +} + +CDialogBase* CMy2015RemoteDlg::GetRemoteWindow(HWND hWnd) +{ + if (!::IsWindow(hWnd)) return FALSE; + EnterCriticalSection(&m_cs); + auto find = m_RemoteWnds.find(hWnd); + auto ret = find == m_RemoteWnds.end() ? NULL : find->second; + LeaveCriticalSection(&m_cs); + return ret; +} + +void CMy2015RemoteDlg::RemoveRemoteWindow(HWND wnd) { + EnterCriticalSection(&m_cs); + m_RemoteWnds.erase(wnd); + LeaveCriticalSection(&m_cs); +} + +LRESULT CALLBACK CMy2015RemoteDlg::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode == HC_ACTION) + { + do { + static CDialogBase* operateWnd = nullptr; + KBDLLHOOKSTRUCT* pKey = (KBDLLHOOKSTRUCT*)lParam; + + // 只在按下时处理 + if (wParam == WM_KEYDOWN) + { + // 检测 Ctrl+C / Ctrl+X + if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && (pKey->vkCode == 'C' || pKey->vkCode == 'X')) { + HWND hFore = ::GetForegroundWindow(); + operateWnd = g_2015RemoteDlg->GetRemoteWindow(hFore); + if (!operateWnd) + g_2015RemoteDlg->m_pActiveSession = nullptr; + } + // 检测 Ctrl+V + else if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && pKey->vkCode == 'V') + { + HWND hFore = ::GetForegroundWindow(); + CDialogBase* dlg = g_2015RemoteDlg->GetRemoteWindow(hFore); + if (dlg) + { + if (dlg == operateWnd)break; + // [1] 本地 -> 远程 + CString strText = GetClipboardText(); + if (!strText.IsEmpty()) { + BYTE* szBuffer = new BYTE[strText.GetLength() + 1]; + szBuffer[0] = COMMAND_SCREEN_SET_CLIPBOARD; + memcpy(szBuffer + 1, strText.GetString(), strText.GetLength()); + dlg->m_ContextObject->Send2Client(szBuffer, strText.GetLength() + 1); + Mprintf("【Ctrl+V】 从本地拷贝到远程 \n"); + SAFE_DELETE_ARRAY(szBuffer); + } + } + else if (g_2015RemoteDlg->m_pActiveSession) + { + // [2] 远程 -> 本地 + BYTE bToken = COMMAND_SCREEN_GET_CLIPBOARD; + g_2015RemoteDlg->m_pActiveSession->m_ContextObject->Send2Client(&bToken, sizeof(bToken)); + Mprintf("【Ctrl+V】 从远程拷贝到本地 \n"); + } + else + { + Mprintf("[Ctrl+V] 没有活动的远程桌面会话 \n"); + } + } + } + } while (0); + } + + // 允许消息继续传递 + return CallNextHookEx(g_2015RemoteDlg->g_hKeyboardHook, nCode, wParam, lParam); +} + +LRESULT CMy2015RemoteDlg::OnSessionActivatedMsg(WPARAM wParam, LPARAM lParam) +{ + CDialogBase* pSession = reinterpret_cast(wParam); + m_pActiveSession = pSession; + return 0; +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 4c2bed9..ed3df64 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -185,6 +185,8 @@ public: ContextObject->hWnd = Dlg->GetSafeHwnd(); ContextObject->hDlg = Dlg; + if(id == IDD_DIALOG_SCREEN_SPY) + m_RemoteWnds[Dlg->GetSafeHwnd()]=(CDialogBase*)Dlg; return 0; } @@ -230,6 +232,13 @@ public: CMenu m_MainMenu; CBitmap m_bmOnline[18]; uint64_t m_superID; + std::map m_RemoteWnds; + CDialogBase* GetRemoteWindow(HWND hWnd); + void RemoveRemoteWindow(HWND wnd); + CDialogBase* m_pActiveSession = nullptr; // ǰỰָ / NULL ʾ + afx_msg LRESULT OnSessionActivatedMsg(WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); + HHOOK g_hKeyboardHook = NULL; enum { STATUS_UNKNOWN = -1, STATUS_RUN = 0, @@ -330,4 +339,5 @@ public: afx_msg void OnExecuteUpload(); afx_msg void OnMachineLogout(); void MachineManage(MachineCommand type); + afx_msg void OnDestroy(); }; diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 27617c1..9e0b320 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -8,6 +8,7 @@ #include #include #include "CGridDialog.h" +#include "2015RemoteDlg.h" // CScreenSpyDlg 对话框 @@ -130,6 +131,7 @@ BEGIN_MESSAGE_MAP(CScreenSpyDlg, CDialog) ON_WM_KILLFOCUS() ON_WM_SIZE() ON_WM_LBUTTONDBLCLK() + ON_WM_ACTIVATE() END_MESSAGE_MAP() @@ -218,6 +220,9 @@ VOID CScreenSpyDlg::OnClose() CWnd* parent = GetParent(); if (parent) parent->SendMessage(WM_CHILD_CLOSED, (WPARAM)this, 0); + extern CMy2015RemoteDlg *g_2015RemoteDlg; + if(g_2015RemoteDlg) + g_2015RemoteDlg->RemoveRemoteWindow(GetSafeHwnd()); // 等待数据处理完毕 if (IsProcessing()) { @@ -861,3 +866,17 @@ void CScreenSpyDlg::OnSize(UINT nType, int cx, int cy) m_wZoom = ((double)m_BitmapInfor_Full->bmiHeader.biWidth) / ((double)(m_CRect.Width())); m_hZoom = ((double)m_BitmapInfor_Full->bmiHeader.biHeight) / ((double)(m_CRect.Height())); } + +void CScreenSpyDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) +{ + CDialogBase::OnActivate(nState, pWndOther, bMinimized); + + CWnd* pMain = AfxGetMainWnd(); + if (!pMain) + return; + + if (nState != WA_INACTIVE){ + // 通知主窗口:远程窗口获得焦点 + ::PostMessage(pMain->GetSafeHwnd(), WM_SESSION_ACTIVATED, (WPARAM)this, 0); + } +} diff --git a/server/2015Remote/ScreenSpyDlg.h b/server/2015Remote/ScreenSpyDlg.h index 6e427f8..6577250 100644 --- a/server/2015Remote/ScreenSpyDlg.h +++ b/server/2015Remote/ScreenSpyDlg.h @@ -109,6 +109,7 @@ public: afx_msg void OnMouseLeave(); afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV ֧ diff --git a/server/2015Remote/stdafx.h b/server/2015Remote/stdafx.h index 3fcd6df..abdc107 100644 --- a/server/2015Remote/stdafx.h +++ b/server/2015Remote/stdafx.h @@ -84,6 +84,7 @@ #define WM_PASSWORDCHECK WM_USER+3021 #define WM_SHOWMESSAGE WM_USER+3022 #define WM_SHOWERRORMSG WM_USER+3023 +#define WM_SESSION_ACTIVATED WM_USER+3024 #ifdef _UNICODE #if defined _M_IX86