Как записать в альтернативный экранный буфер в Windows, используя только стандартную библиотеку? - PullRequest
0 голосов
/ 27 июня 2018

Я работаю над функцией альтернативного экрана для моего кроссплатформенного терминала, управляющего корзиной.

Положение

Когда я хочу что-то записать на консоль, я могу использовать следующий код для записи в текущий стандартный вывод . Это работает в системах UNIX и Windows:

write!(::std::fmt::io::stdout(), "Some text").

Когда я переключаюсь на альтернативный экран, я не хочу записывать на текущий стандартный вывод , а на альтернативный экран. Это работает по-разному в зависимости от того, на какой платформе вы находитесь. Основы те же: мне нужно хранить дескриптор где-нибудь в глобальном масштабе, чтобы я мог перевести сохраненный output handle в альтернативный режим экрана и записать все свои выходные данные, команды и действия в этот сохраненный output handle.

Когда я нахожусь в альтернативном режиме, мой код записывает на альтернативный экран, а в режиме основного экрана мой код записывает на главный экран.

  • Unix

    Для систем UNIX я могу использовать ESC-коды для переключения на альтернативный экран и обратно . Я храню ::std::io::stdout() где-нибудь, и весь мой код UNIX использует этот дескриптор для доступа к терминалу output. В режиме альтернативного экрана все write s, которые я делаю, выполняются на альтернативном экране, а когда на главном экране все write s выполняются на главном экране.

  • Windows

    Для систем Windows я могу использовать WinAPI до , чтобы переключиться на альтернативный экранный буфер . Я создам новый экранный буфер с CreateConsoleScreenBuffer, затем я буду использовать SetConsoleActiveScreenBuffer для изменения активного буфера. Наконец, мне нужно сохранить ручку, полученную из CreateConsoleScreenBuffer. С помощью этого дескриптора вывода я могу записать вывод в буфер альтернативного экрана.

Если бы я не использовал описанный выше способ и не переключился на альтернативный экран, а просто назвал это write!(::std::fmt::io::stdout(), "Some text"), я бы записал на основной экран вместо альтернативного экрана в системах Windows и Unix, поскольку stdout() ручка для стандартного вывода .

Вопрос

Способ, описанный выше, работает до определенного момента; когда я хочу записать в сохраненный дескриптор.

Для Unix я могу сделать следующее:

// (...) some logic to get the handle to the current screen.
let stored_handle: Write = ...;
write!(stored_handle, "Some text);

Но для Windows я мог бы не сделать это:

// (...) some logic to get the handle to the current screen for windows.
let stored_handle: HANDLE = ...;
write!(stored_handle, "Some text);

Я мог бы реализовать std::io::Write для структуры, в которой я храню stdout, чтобы для Windows я создал свою собственную логику для записи в консоль с WinAPI. Если бы я сделал это, я мог бы написать в эту структуру, как показано ниже:

#[cfg(target_os = "windows")]
let storage = WindowsScreenManager::new();
#[cfg(not(target_os = "windows"))]
let storage = UnixScreenManager::new();

write!(storage, "Some text");

Это не идеально для моей ситуации, потому что я не могу использовать экранирующие символы строки Rust, такие как \n \t, моя строка не будет содержать символов новой строки или табуляции при этом. Подумайте, потому что WinAPI не знает эти параметры форматирования. Также я не хочу управлять всей записью в консоли для Windows вручную на моей стороне.

Я действительно хочу использовать WinAPI HANDLE в качестве std::io::Write, чтобы его можно было использовать в макросе write!, как я это делаю в UNIX. Просто сохраните stdout() и запишите в него stdout(), используя макрос write!, но сохраните HANDLE и запишите в него.

Полагаю, это должно работать, так как при вызове println!() или write!(stdout()) в Windows он записывает в стандартный дескриптор вывода текущего процесса. Но теперь я хочу писать в альтернативный дескриптор, а не только в дескриптор по умолчанию. Или я не прав?

Если вышеперечисленное не может быть выполнено, как мне написать на альтернативном экране HANDLE без использования моей собственной реализации для записи в консоль с использованием WinAPI?

...