Какую последовательность нужно передавать в консоль при нажатии стрелок?

@Quttar72

При использовании консольных оболочек, например powershell или bash, при нажатии стрелок влево-вправо мы перемещаем курсор влево и вправо. А при нажатии стрелок вниз-вверх идет переключение по истории команд.

Проведя некоторые опыты, я понял, что все это делается самой консольной оболочкой. То есть, допустим если есть терминал Microsoft, который позволяет запустить тот-же powershell, то совсем не терминал хранит историю команд, а сам powershell. И не сам терминал ограничивает перемещение курсора по строке (не позволяя выйти курсору к промпту).

Вот проблема в том, что я не понимаю, что терминал посылает при этом в powershell? Сейчас моя программа посылает в powershell при нажатии стрелок на клавиатуре CSI последовательности: CUD, CUF, CUU, CUD. По документации они производят перемещение курсора, что они на самом деле буквально и повторяют. (То есть перемещают курсор вниз и вверх, а не показывают историю команд. А так-же перемещают курсор влево и вправо, но без всяких ограничений, то есть курсор может уйти за границы введенной команды и зайти на промпт)

Поэтому мне кажется, что при нажатии этих стрелок, должны отправляться какие-то другие последовательности, то есть буквально, что нажата стрелка, а не вот одна из этих управляющих последовательностей, но я не понимаю как это сделать.

Судя по исходному коду терминала(строки 180 и 390) Microsoft, при нажатии стрелки вверх отправляется эта последовательность: \x1b[1;mA где m должно меняться в зависимости от нажатия ctrl, shift, alt. Если я понял правильно, то m без нажатия этих клавиш заменяется на 1, и тогда итоговая последовательность: \x1b[1;1A Но она фактически просто переводит курсор вверх, то есть почему-то не воспринимается как нажатие стрелки вверх. (не обрабатывает как в том-же терминале).


Ответы на вопрос:

@shurshur

ESC[1;1A будет восприниматься как кнопка только в stdin, в stdout терминал может интерпретировать это как угодно плохо, а перемещение по экранчику вообще делается не стрелками, а последовательностями типа ESC[x;yH.
Не знаю, как это реализовано в Windows, а в Linux для полноценного взаимодействия с другой программой нужно не просто пулять в stdin программы создать отдельный управляемый нашей программой псевдо-терминал, который и будет stdin/stdout/stderr для программы. Иначе программа может определить, что её запустили не из терминала (гуглить isatty), и будет вести себя соответственно.

@MaxKozlov

И вот эти исходники посмотрите https://github.com/PowerShell/PSReadLine
По умолчанию PSReadline входит в комплект и автозапускается на любом PS v5.1+ и наверняка он перехватывает все ваши «кнопки».
Отдельно обратите внимание на MockPSConsole/ и PSReadLine/Movement.cs, PSReadLine/PlatformWindows.cs

@Quttar72

shurshur, я вот как раз и создаю свой псевдотерминал. Аналог терминала Microsoft если можно так сказать) Поэтому и полез внутрь его кода, чтобы понять, что он записывает в stdin по нажатию кнопок стрелок. И вот не пойму почему после ввода в stdin, этой последовательности, она эхом вывелась в stdout? Понятно, что это так и должно работать для обычных букв, но для стрелок powershell должен был вывести не эту же последовательность, а видимо стереть текущие введенные символы и вывести предыдущую команду.

@bingo347

Quttar72, возможно поможет, так как терминал общается с запущенным приложением (тем же powershell) через stdio, то можно для начала написать исследовательскую утилиту, которая переведет stdin в raw mode и будет сохранять то что придет на stdin куда-то в файл (проще будет изучать) или выводит на stdout.
Запускаем утилиту и жмем интересующую кнопку, смотрим что сохранилось.
Ну и да, чтоб полностью воссоздать терминал для других приложений, нужно создавать виртуальный pty, в posix-like системах (linux, bsd, mac os) для этого есть сисколы, с виндой по другому все, но тоже возможно, я не изучал вопрос.

Можно даже еще более интересную штуку сделать:
приложение должно создать виртуальный pty и запустить с ним тот же powershell, а затем проксировать stdin/stdout в этот pty, а заодно куда-то сохранять то что проходит через поток.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *