1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-26 23:04:49 +03:00

record: add support for running on Windows

This commit is contained in:
Wez Furlong 2022-03-25 08:37:38 -07:00
parent e535b2d498
commit 4f2539f8e6
3 changed files with 131 additions and 3 deletions

1
Cargo.lock generated
View File

@ -4596,6 +4596,7 @@ dependencies = [
"wezterm-client", "wezterm-client",
"wezterm-gui-subcommands", "wezterm-gui-subcommands",
"wezterm-term", "wezterm-term",
"winapi 0.3.9",
] ]
[[package]] [[package]]

View File

@ -38,3 +38,16 @@ wezterm-term = { path = "../term" }
[target."cfg(unix)".dependencies] [target."cfg(unix)".dependencies]
termios = "0.3" termios = "0.3"
[target."cfg(windows)".dependencies.winapi]
features = [
"winbase",
"winerror",
"winnls",
"winuser",
"consoleapi",
"handleapi",
"fileapi",
"synchapi",
]
version = "0.3"

View File

@ -8,15 +8,15 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{BufRead, BufReader, BufWriter, Read, Write}; use std::io::{BufRead, BufReader, BufWriter, Read, Write};
use std::mem::MaybeUninit;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use structopt::StructOpt; use structopt::StructOpt;
use termios::{cfmakeraw, tcsetattr, Termios, TCSAFLUSH};
#[cfg(unix)] #[cfg(unix)]
use unix::UnixTty as Tty; use unix::UnixTty as Tty;
use wezterm_term::color::ColorPalette; use wezterm_term::color::ColorPalette;
#[cfg(windows)]
use win::WinTty as Tty;
/// See <https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md> /// See <https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md>
/// for file format specification /// for file format specification
@ -107,9 +107,123 @@ impl Event {
} }
} }
#[cfg(windows)]
mod win {
use super::*;
use filedescriptor::AsRawFileDescriptor;
use std::fs::OpenOptions;
use std::os::windows::io::AsRawHandle;
use winapi::um::consoleapi::*;
use winapi::um::wincon::*;
use winapi::um::winnls::CP_UTF8;
pub struct WinTty {
saved_input: u32,
saved_output: u32,
saved_cp: u32,
read: FileDescriptor,
write: FileDescriptor,
}
impl WinTty {
pub fn new() -> anyhow::Result<Self> {
let read =
FileDescriptor::new(OpenOptions::new().read(true).write(true).open("CONIN$")?);
let write =
FileDescriptor::new(OpenOptions::new().read(true).write(true).open("CONOUT$")?);
let mut saved_input = 0;
let mut saved_output = 0;
let saved_cp;
unsafe {
GetConsoleMode(read.as_raw_file_descriptor(), &mut saved_input);
GetConsoleMode(write.as_raw_file_descriptor(), &mut saved_output);
saved_cp = GetConsoleOutputCP();
SetConsoleOutputCP(CP_UTF8);
}
Ok(Self {
saved_input,
saved_output,
saved_cp,
read,
write,
})
}
pub fn set_cooked(&mut self) -> anyhow::Result<()> {
unsafe {
SetConsoleOutputCP(self.saved_cp);
SetConsoleMode(self.read.as_raw_handle(), self.saved_input);
SetConsoleMode(self.write.as_raw_handle(), self.saved_output);
}
Ok(())
}
pub fn set_raw(&mut self) -> anyhow::Result<()> {
unsafe {
SetConsoleMode(
self.read.as_raw_file_descriptor(),
ENABLE_VIRTUAL_TERMINAL_INPUT,
);
SetConsoleMode(
self.write.as_raw_file_descriptor(),
ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
| ENABLE_VIRTUAL_TERMINAL_PROCESSING
| DISABLE_NEWLINE_AUTO_RETURN,
);
}
Ok(())
}
pub fn get_size(&self) -> anyhow::Result<PtySize> {
let mut info: CONSOLE_SCREEN_BUFFER_INFO = unsafe { std::mem::zeroed() };
let ok = unsafe {
GetConsoleScreenBufferInfo(
self.write.as_raw_handle() as *mut _,
&mut info as *mut _,
)
};
if ok == 0 {
anyhow::bail!(
"GetConsoleScreenBufferInfo failed: {}",
std::io::Error::last_os_error()
);
}
let cols = 1 + (info.srWindow.Right - info.srWindow.Left);
let rows = 1 + (info.srWindow.Bottom - info.srWindow.Top);
Ok(PtySize {
rows: rows as u16,
cols: cols as u16,
pixel_width: 0,
pixel_height: 0,
})
}
pub fn reader(&self) -> anyhow::Result<FileDescriptor> {
Ok(self.read.try_clone()?)
}
pub fn write_all(&mut self, data: &[u8]) -> anyhow::Result<()> {
Ok(self.write.write_all(data)?)
}
}
impl Drop for WinTty {
fn drop(&mut self) {
let _ = self.set_cooked();
}
}
}
#[cfg(unix)]
mod unix { mod unix {
use super::*; use super::*;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use termios::{cfmakeraw, tcsetattr, Termios, TCSAFLUSH};
pub struct UnixTty { pub struct UnixTty {
tty: FileDescriptor, tty: FileDescriptor,
@ -152,7 +266,7 @@ mod unix {
} }
pub fn get_size(&self) -> anyhow::Result<PtySize> { pub fn get_size(&self) -> anyhow::Result<PtySize> {
let mut size = MaybeUninit::<libc::winsize>::uninit(); let mut size = std::mem::MaybeUninit::<libc::winsize>::uninit();
if unsafe { libc::ioctl(self.tty.as_raw_fd(), libc::TIOCGWINSZ as _, &mut size) } != 0 { if unsafe { libc::ioctl(self.tty.as_raw_fd(), libc::TIOCGWINSZ as _, &mut size) } != 0 {
anyhow::bail!( anyhow::bail!(
"failed to ioctl(TIOCGWINSZ): {:#}", "failed to ioctl(TIOCGWINSZ): {:#}",