Terminal: [Conpty] 添加对鼠标输入的支持

创建于 2019-02-18  ·  48评论  ·  资料来源: microsoft/terminal

在: Microsoft Windows [Version 10.0.17763.134]

我已经在我的终端模拟器中实现了 conpty:
https://github.com/wez/wezterm

我可以成功运行target\debug\wezterm.exe来生成控制台应用程序,例如cmd.exe powershell.exebash

我看到的问题是,当我通过cmd.exe间接启动 bash 或直接通过 bash 启动器启动 bash 时,conpty 似乎吞下了鼠标报告转义序列; 我没有看到我的终端解析器收到它们,因此尽管vim配置了set mouse=a但没有有效的鼠标支持。

通过wsl-terminal运行相同的 WSL 安装确实有可用的鼠标支持,并且wezterm一直是我在 Linux 上的日常驱动程序,支持可用鼠标大约一年,因此我们可以排除明显的配置错误vimwezterm的解析器。

我也试过echo -e "\e[?1000h"手动启用来自 shell 的鼠标报告; 通常(在 linux 上和通过 wsl 终端)这会导致终端中的点击将数据发送到 shell(显示为垃圾输入),但是当我的终端使用 conpty 运行时,这些也会在某处被吞没。

我在 pty 中生成的应用程序是否需要特殊的东西才能使用鼠标?

如果您想仔细检查代码的关键部分,相关文件是:
https://github.com/wez/wezterm/blob/master/src/winpty.rs
流程是CreatePipe一对管道, CreatePseudoConsole ,然后通过 threadproc 属性将其传递给生成的孩子,就像 MSDN 文档中的示例和这个 repo 一样。

Area-Interop Issue-Feature Product-Conpty

最有用的评论

仅供可能一直在研究此问题的任何社区成员(/cc @SamuelEnglard!),我们已正式预订开发团队的工作来执行此操作。 我希望我们不会踩到你的脚趾!

所有48条评论

@wez
不幸的是,ConPTY 不会传输鼠标报告(或者,来自托管应用程序的_鼠标报告请求_)。 我们有一个积压项目跟踪这个,我们希望很快就能做到。

不幸的是,我们不能只传递编码的鼠标事件:因为 ConPTY 可以托管标准的 Windows 控制台应用程序,例如期望MOUSE_EVENT s 通过ReadConsoleInput进入,我们将需要做一些翻译。

但是,在所有其他方面,听起来您正确设置了伪控制台。


追踪: MSFT:20469462

@DHowett-MSFT 感谢您的回复!
鼠标报告尚不存在,这有点令人沮丧,但是现在可以使用其余的 pty 内容仍然很好!

除了真的希望 ConPTY 支持鼠标之外,我没有什么可添加的。 随着 alacritty 现在使用 alacritty + ssh + tmux 获得 ConPTY 支持,这是 Windows 上令人难以置信的 linux 终端,现在只缺少鼠标支持。

我是我的 Ubuntu bash shell 中午夜指挥官的重度用户,它工作得很好。 不幸的是,Windows Terminal 0.3.2171.0 中的 Ubuntu shell 选项卡似乎没有将任何鼠标事件发送到 mc 应用程序,这让我很难使用。 我打算发布一个错误,但我认为它会重复这个。

对我而言,发送鼠标事件对于使用 vim 和 tmux 的良好体验至关重要。

只是在这里放弃我对此的支持,加上一点背景。 在过去的一个月里,我停止了双启动,并开始使用 Windows 10 内部构建“快速”环作为我的主要个人机器。 在这一点上,我让 wsl2 完美运行,x410 完美运行,微软终端运行良好,visual studio 代码 wsl2 互操作完美运行,并且 explorer.exe 互操作完美运行。

这个鼠标输入票几乎是唯一阻止我将 wsl2/microsoft 终端称为具有单独分区/开发框的合理替代品的原因。 由于这里的一些地方是开源的,是否有任何关于如何从/dev某个地方查看鼠标设备输入的指示,或者我应该坚持下去?

感谢这一切! 否则我真的很喜欢它:)

再一次投票说/要求鼠标支持会如此甜蜜,并且任何使用 tmux 的人都会非常想念,尽管没有它也可以。

请启用鼠标支持😄

@DHowett-MSFT,抱歉唠叨,有没有计划尽快解决这个问题? 查看在其他问题上分配的标签/优先级,但这不是其中之一,因此只需检查即可。 谢谢你。

@damnskippy优先级被分配给我们需要在收件箱 Windows 控制台主机中修复的内容(由于内部错误截止日期)。 这是一个_巨大的_特性(并且需要一个适当扩展的规范),虽然我们知道 v1.0 需要它,但我们今天并没有积极地致力于它。

如果我们可以像修复错误一样“修复”它,我会很高兴——但它需要的不仅仅是修复。

感谢更新。 您的工作受到赞赏。

我喜欢你在这里所做的,我喜欢,但是在我们获得鼠标支持之前,我们必须用另一个终端来赞美这个终端,这有点违背了这个终端的目的。

没有这个的午夜指挥官是一场噩梦。

鼠标输入通常很有用,比如说,如果社区中的某个人要创建一个可以在 Windows 终端中运行的 DosBox 加载项和配置文件。

我是一个重度 vim 用户; 即使我想念鼠标支持 😢

我刚刚阅读了@cinnamon-msft 博客更新,似乎该团队的目标是在今年年底前实现 1.0? 这是否意味着我们将在年底前获得鼠标支持? 如果是这样,现在是否正在积极开展工作?

这是否意味着我们将在年底前获得鼠标支持?

也许,但没有硬性承诺。 估算完成软件所需的时间与证明 P==NP 一样困难。 我什至要说没有这个终端就不会为 1.0 做好准备。

如果是这样,现在是否正在积极开展工作?

不是现在。 没有人被分配到任务中,通常当团队中的某个人完成一项任务时,他们会分配给自己。

出于好奇,在这里做这件事需要一切吗? 一个雄心勃勃(阅读:疯狂)的开发人员可以接受它并进行公关吗?

当然,雄心勃勃的人绝对可以自己尝试一下。 从哪里开始?

首先,让我们概述一些范围。 鼠标输入有很多工作要做,因此最好从小处着手,然后逐个工作以获得完整的解决方案。 我认为我们应该开始工作的第一件事就是简单的SGR 编码鼠标向上/向下序列。 我们可以处理鼠标滚轮事件,然后可能悬停,然后单击,但我认为单击将解决_大多数_用例。

首先查看InputStateMachineEngine.cppInputStateMachineEngine负责解析通过 conpty 发送的输入,并将其转换为INPUT_RECORD s。 一个有进取心的年轻开发人员希望修改该类,以便也能够解析这些鼠标序列,并将它们转换为INPUT_RECORD s。 一旦你有了INPUT_RECORD s,调用InteractDispatch::WriteInput 。 这会将那些INPUT_RECORD添加到输入缓冲区。 一旦它们在输入缓冲区中,它们将被正常传送到附加的控制台客户端应用程序。

我要注意的事情:

  • 除非我们处于鼠标输入模式,否则 conhost 可能根本不会将 MouseEvents 插入缓冲区。 如果是这种情况,那么我们应该确保也忽略这些序列。
  • 想要从 VT 输入鼠标的应用程序不会得到INPUT_RECORD的流,而是字符流。 在 conhost 中的某个时刻,如果附加的应用程序处于 VT 鼠标模式,我们会尝试将这些鼠标INPUT_RECORD转换为字符流。 如果我们在 _before_ 鼠标事件在缓冲区中进行转换,那么执行上述操作可能不适用于 VT 应用程序(阅读: wsl )。 如果是这种情况,那么我们需要确保为InputStateMachineEngine生成的鼠标事件手动完成从鼠标INPUT_RECORD到 VT 编码鼠标事件的转换。

    • 仔细研究一下,情况确实如此。 不幸的是,我们只为由窗口启动的事件翻译鼠标输入。 看到这个代码:

      https://github.com/microsoft/terminal/blob/2c8b3243dca0c48dd05ecd7b420a7a03b3e19c93/src/interactivity/win32/windowio.cpp#L113 -L129

      terminalMouseInput.HandleMouse将为客户端应用程序合成 VT 序列,但不幸的是它只能从窗口 proc 调用。 因此,我们需要以某种方式公开InputStateMachineEngine调用它的方法(通过InteractDispatch上的新方法),如果该方法失败,则生成适当的INPUT_RECORD s。

    • 从技术上讲,有人可以将terminalMouseInput.HandleMouse调用移动到 InputBuffer 的读取中,并让它尝试在读取时正确地翻译INPUT_RECORD ,但这可能会更复杂。

这个问题怎么办? 鼠标在古老的 Windows 控制台中完美运行。 这是否意味着我必须坚持使用控制台才能解决这个问题?

如果您需要 VT 鼠标支持,是的。

仅供可能一直在研究此问题的任何社区成员(/cc @SamuelEnglard!),我们已正式预订开发团队的工作来执行此操作。 我希望我们不会踩到你的脚趾!

我想过,但一直无法预订我自己的时间如此完美,哈哈!

我只是在玩带有远程开发扩展的 VSCode,发现其中的集成终端实际上​​支持 tmux 中的鼠标模式! 面板选择、窗口选择、面板调整大小和滚轮支持所有工作。 我是这些项目的新手,所以我不知道终端是否是开源 VS Codium 的一部分并且可以用作起点......抱歉,如果这不是真正有用的信息

仅供可能一直在研究此问题的任何社区成员(/cc @SamuelEnglard!),我们已正式预订开发团队的工作来执行此操作。 我希望我们不会踩到你的脚趾!

@DHowett-MSFT @zadjii-msft @bitcrazed你在这里和其他地方就这个问题的交流非常棒; 这是一个成功地让社区参与构建您的软件的典范,它表明了这一点。 您的团队(控制台/WSL/msft-linux)对我安装 Windows(非 nix)的业务负有个人责任。 保持出色的工作🥇

@thinkjrs非常感谢您的客气话。

我们最诚挚地感谢您和我们社区中为终端、Cascadia 代码、WSL 等运行和测试/记录错误/提交问题、想法和拉取请求的每个人。您的反馈会直接影响我们,因为我们会优先考虑工作和计划和设计特点。

当我们说我们为社区并与社区一起构建这些功能时,我们并不是在开玩笑 😜

流程是什么? WSL 中是否有任何功能鼠标? 即tmux面板切换,单击以更改weechatirssi频道/服务器, (n)vim点击, aptitude点击, htop点击等。

流程是什么? WSL 中是否有任何功能鼠标? 即tmux面板切换,单击以更改weechatirssi频道/服务器, (n)vim点击, aptitude点击, htop点击等。

@dmxt目前我使用 wsltty,

流程是什么? WSL 中是否有任何功能鼠标? 即tmux面板切换,单击以更改weechatirssi频道/服务器, (n)vim点击, aptitude点击, htop点击等。

@dmxt目前我使用 wsltty,

我同意您的评论,在过去几年中尝试了所有公知的 Windows 终端仿真器之后,就目前而言,在撰写本文时,wsltty 是最好的。 他们的官方 repo 也很棒,他们为我提供了快速入门的精彩指南。 你不能用机智要求更好,它在各种不同的工作流程和工具中都得到了全面的鼠标支持,没有任何问题。

我注意到 I/O 中的轻微延迟,我认为这是 WSL1 系统的瓶颈。 我在裸机 Linux 上,鼠标输入有 0 毫秒的延迟。

@dmxt @offero我在午夜指挥官微编辑器

请看一下ConEmu是怎么解决的

是否有任何路线图或时间表希望具体何时实施? 似乎是一个非常重要的功能要发布。 令我感到惊讶的是,v1.0 在没有解决这个问题的情况下就发布了。 我猜现在版本控制没有任何意义。

据我所知,支持最新 Microsoft Store 版本的 Windows 终端鼠标输入中的

@fat0troll据我所知,事实并非如此。 即使在带有set mouse=a vim 中,鼠标输入也适用于旧主机,但不适用于 Windows Terminal 1.0.1401.0。

set nocompatible
syntax on
set number
set mouse=a
set backspace=indent,eol,start

使用该 vim 配置,我可以在 vim 的窗口内单击,光标将移动到我单击的位置。 1.0.1401.0,Windows 版本 18368.836(如果它对此有任何影响)。

@kvnxiao我猜你正在使用 OpenSSH_For_Windows_7.7。 其中有一个错误(在 8.x 中已解决)阻止它在鼠标模式下工作。

我们为所有想要接收鼠标输入的 VT 应用程序明确地实现了这一点。

我猜现在版本控制没有任何意义。

没有必要不友善。

关于vim,我尝试使用为windows构建的neovim作为windows可执行文件。 如果其他人说鼠标支持确实适用于 vim(例如,通过 ssh/wsl 等),那么我并不怀疑您,但这表明“完全”支持尚不存在,这提出了更具体的问题题:

与 conhost 目前的能力相比,“完整”鼠标支持的路线图中还剩下什么?

我说的是想要通过 WT 启动支持鼠标输入(并在 conhost 中工作)的基于终端的通用应用程序。 例如,运行几个直接构建为 Windows 可执行文件的基于文本的/终端用户界面应用程序。 这些在双击运行时确实可以正常工作,这需要使用 conhost,但是当通过 Windows 终端运行时,它们最终只用鼠标选择显示的文本。

@niklaskorz当像我这样的人有与此主题有关的相关问题时,对上述评论进行投票和

你完全正确。 您已正确识别为用于从任何终端接收鼠标事件的 Win32 控制台应用程序的工作项,计划用于“终端 1.x”(里程碑),这表明我们希望在现在和 2.0 之间解决它。 我没有比这更细粒度的估计。

感谢您的澄清! 有点遗憾这个工作项无法参与 1.0 的竞争,但我很期待它什么时候可以竞争,希望不会等太久😀。

FIWW,如果您不知道,新的 Powershell Out-ConsoleGridView (https://github.com/PowerShell/GraphicalTools) 是一个杀手级测试用例。 请参阅此处与鼠标相关的跟踪错误: https :

它建立在Terminal.Gui (https://github.com/tig/gui.cs) 之上。

此外,我们刚刚为Terminal.Gui构建了一个新的示例应用程序,你们应该能够使用它来测试鼠标支持,因为它在 WT 中出现。

真的很期待!

有什么办法可以帮助我解决这个问题吗? 对于使用 Terminal.Gui (https://github.com/tig/gui.cs) 构建的 GUI 控制台应用程序来说,这真是令人失望。

@kvnxiao我猜你正在使用 OpenSSH_For_Windows_7.7。 其中有一个错误(在 8.x 中已解决)阻止它在鼠标模式下工作。

我们为所有想要接收鼠标输入的 VT 应用程序明确地实现了这一点。

我猜现在版本控制没有任何意义。

没有必要不友善。

如何将内置 openssh 更新到最新版本?

@kvnxiao我猜你正在使用 OpenSSH_For_Windows_7.7。 其中有一个错误(在 8.x 中已解决)阻止它在鼠标模式下工作。
我们为所有想要接收鼠标输入的 VT 应用程序明确地实现了这一点。

我猜现在版本控制没有任何意义。

没有必要不友善。

如何将内置 openssh 更新到最新版本?

我猜你正在寻找这篇博客文章中描述的东西(从巧克力中安装 Openssh): https :

我猜你正在使用 OpenSSH_For_Windows_7.7。 其中有一个错误(在 8.x 中已解决)阻止它在鼠标模式下工作。

我们为所有想要接收鼠标输入的 VT 应用程序明确地实现了这一点。

@DHowett从这个上下文来看,听起来使用OpenSSH_for_Windows_8.0p1, LibreSSL 2.6.5应该可以工作?

我正在使用终端预览版本通过 SSH 连接到启用了 tmux 鼠标模式的 Ubuntu 机器,但我的鼠标输入似乎仍然只控制终端本身。

我也尝试将服务器升级到 OpenSSH 8.0,但这也无济于事。

这个问题是否仍然阻止这种事情的工作?

啊,8.x 中的x可能是 1。我不知道他们发布了 8.0 版本。

啊,8.x 中的 x 可能是 1。我不知道他们发布了 8.0 版本。

我会试一试。

有用! 太棒了,谢谢!

我开始了解这个问题。

遗憾的是,MS 还没有在 Windows 终端上实现 Win32 API 的鼠标输入功能。
(仅支持 VT 转义序列。)

我试图在我的应用程序中替换 ReadConsoleInputW 和 PeekConsoleInputW
在 Windows 终端上使用鼠标。

首先,我运行以下代码。

SetConsoleMode(hin,  ENABLE_VIRTUAL_TERMINAL_INPUT);
SetConsoleMode(hout, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
char *vt_mouse_input_enable_cmd  = "\x1b[?1000h\x1b[?1003h\x1b[?1006h";
DWORD written;
WriteConsoleA(hout, vt_mouse_input_enable_cmd, strlen(vt_mouse_input_enable_cmd), &written, NULL);

然后,鼠标输入可以作为 VT 转义序列 (sgr-1006) 接收(例如\x1b[<0;10;20M )。

但是,另一个问题出现了。

某些键输入(例如箭头键)也作为 VT 转义序列接收(例如\x1b[A )。

我试图将这些不需要的 VT 转义序列转换为 win32 API 的关键事件,
但这是不完整的。
(虚拟键码和虚拟扫描码随便变零等)

我的代码在这里。
https://gist.github.com/Hamayama/6add968870269f2426716fad79724b31
( PDC_read_console_input_w 和 PDC_peek_console_input_w 是替代函数。)

我想要一种方法来禁用除鼠标输入之外的 VT 转义序列。

例如

char *vt_key_input_disable_cmd = "\x1b[?9XXXl";
DWORD written;
WriteConsoleA(hout, vt_key_input_disable_cmd, strlen(vt_key_input_disable_cmd), &written, NULL);

或者

SetConsoleMode(hin, ENABLE_VIRTUAL_TERMINAL_MOUSE_INPUT_ONLY);

但是,这对未来来说可能是一个错误的想法......

我发现src/terminal/parser/InputStateMachineEngine.cpp: 391没有跟踪鼠标移动(将 SGR VT 序列转换为INPUT_RECORD s)。

换句话说,终端为 ConPTY 发送 VT 序列,但 ConPTY 只监视鼠标按钮的状态。 鼠标坐标的变化被忽略:

src/terminal/parser/InputStateMachineEngine.cpp: 391

success = _UpdateSGRMouseButtonState(id, firstParameter, buttonState, eventFlags);
success = success && _WriteMouseEvent(parameters.at(1), parameters.at(2), buttonState, modifierState, eventFlags);

根据当前支持鼠标输入的状态,可以使用以下选项。

您可以添加坐标跟踪,鼠标移动将在经典控制台应用程序中开始工作。

src/terminal/parser/InputStateMachineEngine.hpp: 172

+ size_t _mouseColumn = 0;
+ size_t _mouseLine = 0;

src/terminal/parser/InputStateMachineEngine.cpp: 391

- success = success && _WriteMouseEvent(parameters.at(1), parameters.at(2), buttonState, modifierState, eventFlags);
+ auto mouseColumn = parameters.at(1).value_or(0);
+ auto mouseLine = parameters.at(2).value_or(0);
+ auto isMoved = mouseColumn! = _mouseColumn || mouseLine! = _mouseLine;
+ if (isMoved)
+ {
+     _mouseColumn = mouseColumn;
+     _mouseLine = mouseLine;
+ }
+ success = (success || isMoved) && _WriteMouseEvent(mouseColumn, mouseLine, buttonState, modifierState, eventFlags);

注意:在启动经典控制台应用程序之前,您需要以 SGR 格式请求鼠标跟踪:

Windows PowerShell

PS C:\Users> [char]0x1b + "[?1003;1004;1006h"

命令提示符

C:\Users> echo Ctrl+[ [?1003;1004;1006h

参数
  • 1003 - ANY_EVENT_MOUSE_MODE
  • 1004 - 任何不支持的模式(例如10019999 )通过 ConPTY 将序列转发到终端本身
  • 1006 - SGR_EXTENDED_MODE

因此,终端将开始向 ConpTY 发送鼠标事件,ConpTY 将开始为经典控制台应用程序生成INPUT_RECORD s。

接得好。 我们必须确保在我们真正采取行动支持这个时解决这个问题 :smile:

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

Wid-Mimosa picture Wid-Mimosa  ·  3评论

DieselMeister picture DieselMeister  ·  3评论

mrmlnc picture mrmlnc  ·  3评论

ghost picture ghost  ·  3评论

NickITGuy picture NickITGuy  ·  3评论