diff --git a/common/commands.h b/common/commands.h index 14d5602..ab6bbea 100644 --- a/common/commands.h +++ b/common/commands.h @@ -442,6 +442,7 @@ enum RemoteDraw { CMD_MOVEWINDOW = 4, CMD_SET_SIZE = 5, CMD_DRAW_CLEAR = 6, + CMD_DRAW_TEXT = 7, }; enum diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 8df84d8..ab8478d 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/CDrawingBoard.cpp b/server/2015Remote/CDrawingBoard.cpp index ec61261..56f416b 100644 --- a/server/2015Remote/CDrawingBoard.cpp +++ b/server/2015Remote/CDrawingBoard.cpp @@ -13,10 +13,20 @@ CDrawingBoard::CDrawingBoard(CWnd* pParent, Server* IOCPServer, CONTEXT_OBJECT* m_bTransport = true; m_bMoving = false; m_bSizing = false; + m_pInputEdit = nullptr; } CDrawingBoard::~CDrawingBoard() { + if (m_pInputEdit != nullptr) { + m_pInputEdit->DestroyWindow(); + delete m_pInputEdit; + m_pInputEdit = nullptr; + } + if (m_font.GetSafeHandle()) + m_font.DeleteObject(); + if (m_pen.GetSafeHandle()) + m_pen.DeleteObject(); } void CDrawingBoard::DoDataExchange(CDataExchange* pDX) @@ -32,11 +42,13 @@ BEGIN_MESSAGE_MAP(CDrawingBoard, CDialog) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_WINDOWPOSCHANGED() + ON_WM_RBUTTONDOWN() ON_COMMAND(ID_DRAWING_TOPMOST, &CDrawingBoard::OnDrawingTopmost) ON_COMMAND(ID_DRAWING_TRANSPORT, &CDrawingBoard::OnDrawingTransport) ON_COMMAND(ID_DRAWING_MOVE, &CDrawingBoard::OnDrawingMove) ON_COMMAND(ID_DRAWING_SIZE, &CDrawingBoard::OnDrawingSize) - ON_COMMAND(ID_DRAWING_CLEAR, &CDrawingBoard::OnDrawingClear) + ON_COMMAND(IDM_CLEAR_DRAWING, &CDrawingBoard::OnDrawingClear) + ON_COMMAND(ID_DRAWING_TEXT, &CDrawingBoard::OnDrawingText) END_MESSAGE_MAP() void CDrawingBoard::OnReceiveComplete() @@ -58,8 +70,7 @@ void CDrawingBoard::OnPaint() { CPaintDC dc(this); - CPen pen(PS_SOLID, 2, RGB(0, 0, 0)); - CPen* pOldPen = dc.SelectObject(&pen); + CPen* pOldPen = dc.SelectObject(&m_pen); for (const auto& path : m_paths) { @@ -77,6 +88,15 @@ void CDrawingBoard::OnPaint() dc.LineTo(m_currentPath[i]); } + CFont* pOldFont = dc.SelectObject(&m_font); + dc.SetTextColor(RGB(0, 0, 0)); + dc.SetBkMode(TRANSPARENT); + + for (const auto& entry : m_Texts) + dc.TextOut(entry.first.x, entry.first.y, entry.second); + + dc.SelectObject(pOldFont); + dc.SelectObject(pOldPen); } @@ -162,7 +182,7 @@ void CDrawingBoard::OnDrawingTopmost() void CDrawingBoard::OnDrawingTransport() { m_bTransport = !m_bTransport; - BYTE cmd[2] = { CMD_TRANSPORT, m_bTransport }; + BYTE cmd[2] = { CMD_TRANSPORT, m_bTransport ? 150 : 255 }; m_ContextObject->Send2Client((PBYTE)cmd, sizeof(cmd)); HMENU hMenu = ::GetMenu(this->GetSafeHwnd()); int n = m_bTransport ? MF_CHECKED : MF_UNCHECKED; @@ -199,6 +219,13 @@ BOOL CDrawingBoard::OnInitDialog() str.Format("%s - 画板演示", m_IPAddress); SetWindowText(str); + m_font.CreateFont( + 20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial")); + + m_pen.CreatePen(PS_SOLID, 2, RGB(0, 0, 0)); + HMENU hMenu = ::GetMenu(this->GetSafeHwnd()); ::CheckMenuItem(hMenu, ID_DRAWING_TOPMOST, MF_BYCOMMAND | MF_CHECKED); ::CheckMenuItem(hMenu, ID_DRAWING_TRANSPORT, MF_BYCOMMAND | MF_CHECKED); @@ -211,8 +238,103 @@ void CDrawingBoard::OnDrawingClear() { m_paths.clear(); m_currentPath.clear(); + m_Texts.clear(); BYTE cmd[2] = { CMD_DRAW_CLEAR, 0 }; m_ContextObject->Send2Client((PBYTE)cmd, sizeof(cmd)); if (m_hWnd && IsWindow(m_hWnd)) ::InvalidateRect(m_hWnd, NULL, TRUE); // 重绘整个窗口,清除痕迹 } + +void CDrawingBoard::OnRButtonDown(UINT nFlags, CPoint point) +{ + m_RightClickPos = point; // 记录鼠标点 + ClientToScreen(&m_RightClickPos); // 变为屏幕坐标 + + CMenu menu; + menu.LoadMenu(IDR_MENU_POPUP); + CMenu* pSubMenu = menu.GetSubMenu(0); + + if (pSubMenu) + pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, m_RightClickPos.x, m_RightClickPos.y, this); + + CDialog::OnRButtonDown(nFlags, point); +} + + +void CDrawingBoard::OnDrawingText() +{ + if (m_pInputEdit != nullptr) { + m_pInputEdit->DestroyWindow(); + delete m_pInputEdit; + m_pInputEdit = nullptr; + } + + CPoint ptClient = m_RightClickPos; + ScreenToClient(&ptClient); + + m_pInputEdit = new CEdit(); + m_pInputEdit->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, + CRect(ptClient.x, ptClient.y, ptClient.x + 200, ptClient.y + 25), + this, 1234); // 控件 ID 可自定 + m_pInputEdit->SetFocus(); +} + +BOOL CDrawingBoard::PreTranslateMessage(MSG* pMsg) +{ + if (m_pInputEdit && pMsg->hwnd == m_pInputEdit->m_hWnd) + { + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) + { + CString strText; + m_pInputEdit->GetWindowText(strText); + + // TODO: 将文字位置和内容加入列表并触发绘图 + if (!strText.IsEmpty()) { + CPoint ptClient = m_RightClickPos; + ScreenToClient(&ptClient); + m_Texts.push_back(std::make_pair(ptClient, strText)); + SendTextsToRemote(ptClient, strText); + } + + m_pInputEdit->DestroyWindow(); + delete m_pInputEdit; + m_pInputEdit = nullptr; + + return TRUE; // 吞掉回车 + } + } + return CDialog::PreTranslateMessage(pMsg); +} + +void CDrawingBoard::SendTextsToRemote(const CPoint& pt, const CString& text) +{ + if (text.IsEmpty()) return; + + // 1. 转换为 UTF-8 + // CString 是 TCHAR 类型,若项目是多字节字符集,则需先转为宽字符 +#ifdef _UNICODE + LPCWSTR lpWideStr = text; +#else + // 从 ANSI 转为宽字符 + int wideLen = MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0); + std::wstring wideStr(wideLen, 0); + MultiByteToWideChar(CP_ACP, 0, text, -1, &wideStr[0], wideLen); + LPCWSTR lpWideStr = wideStr.c_str(); +#endif + + int utf8Len = WideCharToMultiByte(CP_UTF8, 0, lpWideStr, -1, NULL, 0, NULL, NULL); + if (utf8Len <= 1) return; // 空或失败 + + std::vector utf8Text(utf8Len - 1); // 去掉末尾的 \0 + WideCharToMultiByte(CP_UTF8, 0, lpWideStr, -1, utf8Text.data(), utf8Len - 1, NULL, NULL); + + // 2. 构造发送 buffer + std::vector buffer; + buffer.push_back(CMD_DRAW_TEXT); // 自定义命令码 + + buffer.insert(buffer.end(), (char*)&pt, (char*)&pt + sizeof(CPoint)); + buffer.insert(buffer.end(), utf8Text.begin(), utf8Text.end()); + + // 3. 发送 + m_ContextObject->Send2Client((LPBYTE)buffer.data(), (ULONG)buffer.size()); +} diff --git a/server/2015Remote/CDrawingBoard.h b/server/2015Remote/CDrawingBoard.h index 4484044..6ec65b0 100644 --- a/server/2015Remote/CDrawingBoard.h +++ b/server/2015Remote/CDrawingBoard.h @@ -24,6 +24,7 @@ public: afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); protected: virtual void DoDataExchange(CDataExchange* pDX); @@ -32,6 +33,10 @@ protected: DECLARE_MESSAGE_MAP() + BOOL PreTranslateMessage(MSG* pMsg); + + void SendTextsToRemote(const CPoint& pt, const CString& inputText); + private: bool m_bTopMost; // 置顶 bool m_bTransport; // 半透明 @@ -40,6 +45,11 @@ private: bool m_bDrawing; // 是否正在绘图 std::vector m_currentPath; // 当前路径点 std::vector> m_paths; // 所有路径 + CPoint m_RightClickPos; // 右键点击位置 + CEdit* m_pInputEdit = nullptr; // 类成员变量 + std::vector> m_Texts; + CFont m_font; // 添加字体成员 + CPen m_pen; // 画笔 public: afx_msg void OnDrawingTopmost(); afx_msg void OnDrawingTransport(); @@ -47,4 +57,5 @@ public: afx_msg void OnDrawingSize(); virtual BOOL OnInitDialog(); afx_msg void OnDrawingClear(); + afx_msg void OnDrawingText(); }; diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 92b2eaa..a3f52b2 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ