57 lines
1.7 KiB
Rust
57 lines
1.7 KiB
Rust
use std::{
|
|
io::{self, Error, ErrorKind, Write},
|
|
time::Duration,
|
|
};
|
|
|
|
use crate::{
|
|
event::{filter::CursorPositionFilter, poll_internal, read_internal, InternalEvent},
|
|
terminal::{disable_raw_mode, enable_raw_mode, sys::is_raw_mode_enabled},
|
|
};
|
|
|
|
/// Returns the cursor position (column, row).
|
|
///
|
|
/// The top left cell is represented as `(0, 0)`.
|
|
///
|
|
/// On unix systems, this function will block and possibly time out while
|
|
/// [`crossterm::event::read`](crate::event::read) or [`crossterm::event::poll`](crate::event::poll) are being called.
|
|
pub fn position() -> io::Result<(u16, u16)> {
|
|
if is_raw_mode_enabled() {
|
|
read_position_raw()
|
|
} else {
|
|
read_position()
|
|
}
|
|
}
|
|
|
|
fn read_position() -> io::Result<(u16, u16)> {
|
|
enable_raw_mode()?;
|
|
let pos = read_position_raw();
|
|
disable_raw_mode()?;
|
|
pos
|
|
}
|
|
|
|
fn read_position_raw() -> io::Result<(u16, u16)> {
|
|
// Use `ESC [ 6 n` to and retrieve the cursor position.
|
|
let mut stdout = io::stdout();
|
|
stdout.write_all(b"\x1B[6n")?;
|
|
stdout.flush()?;
|
|
|
|
loop {
|
|
match poll_internal(Some(Duration::from_millis(2000)), &CursorPositionFilter) {
|
|
Ok(true) => {
|
|
if let Ok(InternalEvent::CursorPosition(x, y)) =
|
|
read_internal(&CursorPositionFilter)
|
|
{
|
|
return Ok((x, y));
|
|
}
|
|
}
|
|
Ok(false) => {
|
|
return Err(Error::new(
|
|
ErrorKind::Other,
|
|
"The cursor position could not be read within a normal duration",
|
|
));
|
|
}
|
|
Err(_) => {}
|
|
}
|
|
}
|
|
}
|