1 | use std::{
|
2 | io::{self, Error, ErrorKind, Write},
|
3 | time::Duration,
|
4 | };
|
5 |
|
6 | use crate::{
|
7 | event::{filter::CursorPositionFilter, poll_internal, read_internal, InternalEvent},
|
8 | terminal::{disable_raw_mode, enable_raw_mode, sys::is_raw_mode_enabled},
|
9 | };
|
10 |
|
11 | /// Returns the cursor position (column, row).
|
12 | ///
|
13 | /// The top left cell is represented as `(0, 0)`.
|
14 | ///
|
15 | /// On unix systems, this function will block and possibly time out while
|
16 | /// [`crossterm::event::read`](crate::event::read) or [`crossterm::event::poll`](crate::event::poll) are being called.
|
17 | pub fn position() -> io::Result<(u16, u16)> {
|
18 | if is_raw_mode_enabled() {
|
19 | read_position_raw()
|
20 | } else {
|
21 | read_position()
|
22 | }
|
23 | }
|
24 |
|
25 | fn read_position() -> io::Result<(u16, u16)> {
|
26 | enable_raw_mode()?;
|
27 | let pos: Result<(u16, u16), Error> = read_position_raw();
|
28 | disable_raw_mode()?;
|
29 | pos
|
30 | }
|
31 |
|
32 | fn read_position_raw() -> io::Result<(u16, u16)> {
|
33 | // Use `ESC [ 6 n` to and retrieve the cursor position.
|
34 | let mut stdout = io::stdout();
|
35 | stdout.write_all(b" \x1B[6n" )?;
|
36 | stdout.flush()?;
|
37 |
|
38 | loop {
|
39 | match poll_internal(Some(Duration::from_millis(2000)), &CursorPositionFilter) {
|
40 | Ok(true) => {
|
41 | if let Ok(InternalEvent::CursorPosition(x, y)) =
|
42 | read_internal(&CursorPositionFilter)
|
43 | {
|
44 | return Ok((x, y));
|
45 | }
|
46 | }
|
47 | Ok(false) => {
|
48 | return Err(Error::new(
|
49 | ErrorKind::Other,
|
50 | "The cursor position could not be read within a normal duration" ,
|
51 | ));
|
52 | }
|
53 | Err(_) => {}
|
54 | }
|
55 | }
|
56 | }
|
57 | |