Merge pull request #93 from IGI-111/cursor_pos

added cursor position detection
This commit is contained in:
ticki 2017-03-24 21:50:57 +01:00 committed by GitHub
commit 7351aa3f16
4 changed files with 69 additions and 10 deletions

View File

@ -1,7 +1,7 @@
extern crate termion; extern crate termion;
use termion::event::*; use termion::event::*;
use termion::cursor; use termion::cursor::{self, DetectCursorPos};
use termion::input::{TermRead, MouseTerminal}; use termion::input::{TermRead, MouseTerminal};
use termion::raw::IntoRawMode; use termion::raw::IntoRawMode;
use std::io::{self, Write}; use std::io::{self, Write};
@ -26,6 +26,14 @@ fn main() {
MouseEvent::Release(a, b) | MouseEvent::Release(a, b) |
MouseEvent::Hold(a, b) => { MouseEvent::Hold(a, b) => {
write!(stdout, "{}", cursor::Goto(a, b)).unwrap(); write!(stdout, "{}", cursor::Goto(a, b)).unwrap();
let (x, y) = stdout.cursor_pos().unwrap();
write!(stdout,
"{}{}Cursor is at: ({},{}){}",
cursor::Goto(5, 5),
termion::clear::UntilNewline,
x,
y,
cursor::Goto(a, b)).unwrap();
} }
} }
} }

View File

@ -13,7 +13,7 @@
//! ``` //! ```
use std::fmt; use std::fmt;
use raw::RawTerminal; use raw::CONTROL_SEQUENCE_TIMEOUT;
use std::io::{self, Write, Read}; use std::io::{self, Write, Read};
use std::time::{SystemTime, Duration}; use std::time::{SystemTime, Duration};
use async::async_stdin; use async::async_stdin;
@ -175,7 +175,7 @@ pub trait DetectColors {
fn available_colors(&mut self) -> io::Result<u16>; fn available_colors(&mut self) -> io::Result<u16>;
} }
impl<W: Write> DetectColors for RawTerminal<W> { impl<W: Write> DetectColors for W {
fn available_colors(&mut self) -> io::Result<u16> { fn available_colors(&mut self) -> io::Result<u16> {
let mut stdin = async_stdin(); let mut stdin = async_stdin();
@ -210,11 +210,8 @@ impl<W: Write> DetectColors for RawTerminal<W> {
} }
} }
/// The timeout of an escape code control sequence, in milliseconds.
const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
/// Detect a color using OSC 4. /// Detect a color using OSC 4.
fn detect_color<W: Write>(stdout: &mut RawTerminal<W>, fn detect_color(stdout: &mut Write,
stdin: &mut Read, stdin: &mut Read,
color: u16) color: u16)
-> io::Result<bool> { -> io::Result<bool> {

View File

@ -1,6 +1,10 @@
//! Cursor movement. //! Cursor movement.
use std::fmt; use std::fmt;
use std::io::{self, Write, Error, ErrorKind, Read};
use async::async_stdin;
use std::time::{SystemTime, Duration};
use raw::CONTROL_SEQUENCE_TIMEOUT;
derive_csi_sequence!("Hide the cursor.", Hide, "?25l"); derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
derive_csi_sequence!("Show the cursor.", Show, "?25h"); derive_csi_sequence!("Show the cursor.", Show, "?25h");
@ -76,3 +80,50 @@ impl fmt::Display for Down {
write!(f, csi!("{}B"), self.0) write!(f, csi!("{}B"), self.0)
} }
} }
/// Types that allow detection of the cursor position.
pub trait DetectCursorPos {
/// Get the (1,1)-based cursor position from the terminal.
fn cursor_pos(&mut self) -> io::Result<(u16, u16)>;
}
impl<W: Write> DetectCursorPos for W {
fn cursor_pos(&mut self) -> io::Result<(u16, u16)> {
let mut stdin = async_stdin();
// Where is the cursor?
// Use `ESC [ 6 n`.
write!(self, "\x1B[6n")?;
self.flush()?;
let mut buf: [u8; 1] = [0];
let mut read_chars = Vec::new();
let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
let now = SystemTime::now();
// Either consume all data up to R or wait for a timeout.
while buf[0] != b'R' && now.elapsed().unwrap() < timeout {
if stdin.read(&mut buf)? > 0 {
read_chars.push(buf[0]);
}
}
if read_chars.len() == 0 {
return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out."));
}
// The answer will look like `ESC [ Cy ; Cx R`.
read_chars.pop(); // remove trailing R.
let read_str = String::from_utf8(read_chars).unwrap();
let beg = read_str.rfind('[').unwrap();
let coords: String = read_str.chars().skip(beg+1).collect();
let mut nums = coords.split(';');
let cy = nums.next().unwrap().parse::<u16>().unwrap();
let cx = nums.next().unwrap().parse::<u16>().unwrap();
Ok((cx, cy))
}
}

View File

@ -25,6 +25,9 @@
use std::io::{self, Write}; use std::io::{self, Write};
use std::ops; use std::ops;
/// The timeout of an escape code control sequence, in milliseconds.
pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when /// A terminal restorer, which keeps the previous state of the terminal, and restores it, when
/// dropped. /// dropped.
/// ///