From 5a92c3306f097901604539749d7cd98f59e471e9 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Thu, 14 May 2026 23:57:48 +0200 Subject: [PATCH] Feature: Web remote terminal (xterm.js + mobile UX polish) --- server/2015Remote/2015Remote.rc | Bin 155382 -> 155820 bytes server/2015Remote/2015RemoteDlg.cpp | 37 +- server/2015Remote/2015Remote_vs2015.vcxproj | 5 + .../2015Remote_vs2015.vcxproj.filters | 5 + server/2015Remote/WebPage.h | 342 +++++++++++++++++- server/2015Remote/WebService.cpp | 306 +++++++++++++++- server/2015Remote/WebService.h | 36 ++ server/2015Remote/res/web/fit.min.js | 8 + server/2015Remote/res/web/xterm.css | 209 +++++++++++ server/2015Remote/res/web/xterm.min.js | 8 + server/2015Remote/resource.h | 5 +- 11 files changed, 953 insertions(+), 8 deletions(-) create mode 100644 server/2015Remote/res/web/fit.min.js create mode 100644 server/2015Remote/res/web/xterm.css create mode 100644 server/2015Remote/res/web/xterm.min.js diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 01705bdf7487c5aa36f77949a4954aa799c81c6e..c5e25989197cf1aeb3841ac314ca613122ea2dcc 100644 GIT binary patch delta 254 zcmeyimvhZQ&W0AoElkf`rpLH2afpXAxH32~#4|)NgaBDV48B0N7eny$KszSq$p?hE zJj)qU8Il-cfUtt01jsI8$Ysz2;!K7-Af3ff%%H@;%fQ9p$>0Li9?yWyKxc+vpplBU wOx`$*O9mQ4j6rTdYeJwdG_+*02Dwlc;lebat4dH^H~qdN)9&rlT$vIi0X~B@HUIzs delta 19 bcmZ2;kn`JK&W0AoElkf`w$E{65|9D_TY?AO diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index e6a35cd..c70cbca 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -4587,6 +4587,12 @@ BOOL CALLBACK CMy2015RemoteDlg::OfflineProc(CONTEXT_OBJECT* ContextObject) if (!g_2015RemoteDlg || g_2015RemoteDlg->isClosed) return FALSE; + // Web 终端的 shell 子上下文断开:通知 WebService 清理 session(含通知前端)。 + // 在 RemoveFromHostList 之前做,避免 ctx 被释放后 WebService 还持有悬空指针。 + if (WebService().IsRunning() && WebService().IsTerminalContext(ContextObject)) { + WebService().OnTerminalClosed(ContextObject); + } + SOCKET nSocket = ContextObject->sClientSocket; CDialogBase* p = (CDialogBase*)ContextObject->hDlg; @@ -4918,6 +4924,19 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) unsigned cmd = ContextObject->InDeCompressedBuffer.GetBYTE(0); LPBYTE szBuffer = ContextObject->InDeCompressedBuffer.GetBuffer(); unsigned len = ContextObject->InDeCompressedBuffer.GetBufferLen(); + + // ===== Web 终端的 shell 子上下文:被 WebService 接管时,所有数据走 OnTerminalData ===== + // 这里覆盖一个特殊路径:Web 接管的 shell 子上下文不开 MFC 对话框,hDlg 一直为 NULL, + // 因此每个数据包都会走到这个 MessageHandle。我们把字节直接转发给 WebService。 + if (WebService().IsRunning() && WebService().IsTerminalContext(ContextObject)) { + if (len == 1 && cmd == TOKEN_TERMINAL_CLOSE) { + WebService().OnTerminalClosed(ContextObject); + } else { + WebService().OnTerminalData(ContextObject, szBuffer, len); + } + return; + } + // 【L】:主机上下线和授权 // 【x】:对话框相关功能 switch (cmd) { @@ -5676,11 +5695,25 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) g_2015RemoteDlg->SendMessage(WM_OPENTALKDIALOG, 0, (LPARAM)ContextObject); break; } - case TOKEN_SHELL_START: { // Windows 远程终端 + case TOKEN_SHELL_START: { // Windows 老 cmd 管道终端 + // 如果是 Web 触发的 term_open,把 shell 子上下文交给 WebService 而不是开 MFC dialog + uint64_t devId = ContextObject->GetClientID(); + if (WebService().IsRunning() && WebService().IsTermPending(devId)) { + WebService().RegisterTerminalContext(devId, ContextObject, /*isPty*/false); + // hDlg 留 NULL:后续数据继续走 MessageHandle 顶部的 IsTerminalContext 分支 + break; + } g_2015RemoteDlg->SendMessage(WM_OPENSHELLDIALOG, 0, (LPARAM)ContextObject); break; } - case TOKEN_TERMINAL_START: { // Linux PTY 终端 (WebView2 + xterm.js) + case TOKEN_TERMINAL_START: { // 现代 PTY 终端 (Linux/macOS/Windows ConPTY) + // 同上:Web 触发优先级最高,直接 WebService 接管 + uint64_t devId = ContextObject->GetClientID(); + if (WebService().IsRunning() && WebService().IsTermPending(devId)) { + WebService().RegisterTerminalContext(devId, ContextObject, /*isPty*/true); + break; + } + // 三个前置条件,缺任何一个都回退到经典终端,并把原因贴到信息列表。 // SYSTEM 场景:WebView2 不支持 LocalSystem token,会出现"窗口能弹但页面空白", // 显式拦截一次,避免用户误以为是 bug。 diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 45c6567..0749146 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -601,6 +601,11 @@ + + + + + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 20c26e6..15ac41e 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -340,4 +340,9 @@ {17217547-dc35-4a87-859c-e8559529a909} + + + + + \ No newline at end of file diff --git a/server/2015Remote/WebPage.h b/server/2015Remote/WebPage.h index 25e0da3..44e151a 100644 --- a/server/2015Remote/WebPage.h +++ b/server/2015Remote/WebPage.h @@ -22,6 +22,8 @@ inline std::string GetWebPageHTML() { + +