Merge pull request #93 from IGI-111/cursor_pos
added cursor position detection
This commit is contained in:
		
						commit
						7351aa3f16
					
				|  | @ -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(); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
							
								
								
									
										15
									
								
								src/color.rs
								
								
								
								
							
							
						
						
									
										15
									
								
								src/color.rs
								
								
								
								
							|  | @ -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,14 +210,11 @@ 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> { | ||||||
|     // Is the color available?
 |     // Is the color available?
 | ||||||
|     // Use `ESC ] 4 ; color ; ? BEL`.
 |     // Use `ESC ] 4 ; color ; ? BEL`.
 | ||||||
|     write!(stdout, "\x1B]4;{};?\x07", color)?; |     write!(stdout, "\x1B]4;{};?\x07", color)?; | ||||||
|  |  | ||||||
|  | @ -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