1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
use std::fs::{File, OpenOptions}; use std::io; use std::io::{Read, Write}; pub fn query_start(esc: &[u8]) -> io::Result<File> { let mut tty = OpenOptions::new().read(true).write(true).open("/dev/tty")?; tty.write_all(esc)?; tty.flush()?; Ok(tty) } enum Curp { Nil, Esc, Esc2, Y(u16, u16), Semi(u16), X(u16, u16, u16), } fn ascii2digit(x: u8) -> u16 { (x - b'0') as u16 } fn get_cursor_xy_with_esc(esc: &[u8]) -> io::Result<(u16, u16)> { let mut state = Curp::Nil; for b in query_start(esc)?.bytes() { let b = b?; state = match (state, b) { (Curp::Nil, b'\x1b') => Curp::Esc, (Curp::Nil, _) => Curp::Nil, (Curp::Esc, b'[') => Curp::Esc2, (Curp::Esc, _) => Curp::Nil, (Curp::Esc2, b'0'..=b'9') => Curp::Y(10, ascii2digit(b)), (Curp::Esc2, _) => Curp::Nil, (Curp::Y(_, y), b';') => Curp::Semi(y), (Curp::Y(z, y), b'0'..=b'9') => Curp::Y(z * 10, y + ascii2digit(b) * z), (Curp::Y(_, _), _) => Curp::Nil, (Curp::Semi(y), b'0'..=b'9') => Curp::X(10, ascii2digit(b), y), (Curp::Semi(_), _) => Curp::Nil, (Curp::X(_, x, y), b'R') => return Ok((x, y)), (Curp::X(z, x, y), b'0'..=b'9') => Curp::X(z * 10, x + ascii2digit(b) * z, y), (Curp::X(_, _, _), _) => Curp::Nil, } } Err(io::Error::new( io::ErrorKind::NotFound, "End of tty before cursor pos matched", )) } pub fn get_cursor_xy() -> io::Result<(u16, u16)> { get_cursor_xy_with_esc(b"\x1b[6n") } pub fn get_tty_wh_dirty() -> io::Result<(u16, u16)> { get_cursor_xy_with_esc(b"\x1b[999;999H\x1b[6n") } pub fn get_tty_wh() -> io::Result<(u16, u16)> { get_cursor_xy_with_esc(b"\x1b7\x1b[999;999H\x1b[6n\x1b8") }