added cursor position detection
This solves #85 in a similar fashion as the color amount detection: the cursor module now provides a trait that adds a `cursor_pos()` method to an instance of `Write`. It also corrects that previous implementation somewhat by making the `CONTROL_SEQUENCE_TIMEOUT` a member of the raw module and implementing `DetectColors` for any instance of `Write` rather than just `RawTerminal` (`MouseTerminal` for instance works as well).
This commit is contained in:
parent
95233e9e5c
commit
0758c07ab7
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<W: Write>(stdout: &mut W,
|
||||||
stdin: &mut Read,
|
stdin: &mut Read,
|
||||||
color: u16)
|
color: u16)
|
||||||
-> io::Result<bool> {
|
-> io::Result<bool> {
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue