minicrossterm/crossterm_cursor/src/sys/unix.rs
Timon b8d4255bac
Fixed some Bugs. (#118)
- Terminal size Linux was not 0-based.
- Windows mouse input event position was 0-based and should be 1-based
- Result, ErrorKind are made re-exported
- Fixed some special key combination detections for UNIX systems
- Made FreeBSD compile.
2019-04-17 16:24:58 +02:00

90 lines
2.5 KiB
Rust

use crossterm_utils::sys::unix;
use std::io::{self, Error, ErrorKind, Read, Write};
/// Get the cursor position based on the current platform.
#[cfg(unix)]
pub fn get_cursor_position() -> (u16, u16) {
if let Ok(pos) = pos() {
pos
} else {
(0, 0)
}
}
pub fn pos() -> io::Result<(u16, u16)> {
// if we enable raw modes with screen, this could cause problems if raw mode is already enabled in application.
// I am not completely happy with this approach so feel free to find an other way.
unsafe {
if !unix::RAW_MODE_ENABLED_BY_USER || !unix::RAW_MODE_ENABLED_BY_SYSTEM {
// set this boolean so that we know that the systems has enabled raw mode.
unix::RAW_MODE_ENABLED_BY_SYSTEM = true;
unix::into_raw_mode()?;
}
}
// Where is the cursor?
// Use `ESC [ 6 n`.
let mut stdout = io::stdout();
// Write command
stdout.write_all(b"\x1B[6n")?;
stdout.flush()?;
let mut buf = [0u8; 2];
// Expect `ESC[`
io::stdin().read_exact(&mut buf)?;
if buf[0] != 0x1B || buf[1] as char != '[' {
return Err(Error::new(ErrorKind::Other, "test"));
}
// Read rows and cols through a ad-hoc integer parsing function
let read_num: fn() -> Result<(i32, char), Error> = || -> Result<(i32, char), Error> {
let mut num = 0;
let mut c: char;
loop {
let mut buf = [0u8; 1];
io::stdin().read_exact(&mut buf)?;
c = buf[0] as char;
if let Some(d) = c.to_digit(10) {
num = if num == 0 { 0 } else { num * 10 };
num += d as i32;
} else {
break;
}
}
Ok((num, c))
};
// Read rows and expect `;`
let (rows, c) = read_num()?;
if c != ';' {
return Err(Error::new(ErrorKind::Other, "test"));
}
// Read cols
let (cols, c) = read_num()?;
// Expect `R`
let res = if c == 'R' {
// subtract one to get 0-based coords
Ok(((cols - 1) as u16, (rows - 1) as u16))
} else {
return Err(Error::new(ErrorKind::Other, "test"));
};
// If raw mode is enabled from else where in the application (by the user) we do not want to disable raw modes.
// I am not completely happy with this approach so feel free to find an other way.
unsafe {
if unix::RAW_MODE_ENABLED_BY_SYSTEM && !unix::RAW_MODE_ENABLED_BY_USER {
unix::RAW_MODE_ENABLED_BY_SYSTEM = false;
unix::disable_raw_mode()?;
}
}
res
}