Raw Screen Cursor Position UNIX Bug Fix (#134)

This commit is contained in:
Timon 2019-05-03 20:15:07 +02:00 committed by GitHub
parent d31d712a38
commit 0bfebb338d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 57 additions and 119 deletions

View File

@ -32,12 +32,12 @@ members = [
]
[dependencies]
crossterm_screen = { optional = true, version = "0.2.1" }
crossterm_cursor = { optional = true, version = "0.2.1" }
crossterm_screen = { optional = true, path = "./crossterm_screen" }
crossterm_cursor = { optional = true, path = "./crossterm_cursor" }
crossterm_terminal = { optional = true, version = "0.2.2" }
crossterm_style = { optional = true, version = "0.3.1" }
crossterm_input = { optional = true, version = "0.3.3" }
crossterm_utils = { optional = false, version = "0.2.1" }
crossterm_style = { optional = true, path = "./crossterm_style" }
crossterm_input = { optional = true, path = "./crossterm_input" }
crossterm_utils = { optional = false, path = "./crossterm_utils" }
[lib]
name = "crossterm"

View File

@ -16,4 +16,4 @@ winapi = { version = "0.3.7", features = ["wincon","winnt","minwindef"] }
crossterm_winapi = "0.1.2"
[dependencies]
crossterm_utils = "0.2.1"
crossterm_utils = { path = "../crossterm_utils" }

View File

@ -1,28 +1,32 @@
use crossterm_utils::sys::unix;
use crossterm_utils::sys::unix::{self, RAW_MODE_ENABLED};
use std::io::{self, Error, ErrorKind, Read, Write};
/// Get the cursor position based on the current platform.
#[cfg(unix)]
pub fn get_cursor_position() -> (u16, u16) {
if let Ok(pos) = pos() {
pos
if unsafe { RAW_MODE_ENABLED } {
if let Ok(pos) = pos_raw() {
pos
} else {
(0, 0)
}
} else {
(0, 0)
if let Ok(pos) = pos() {
pos
} else {
(0, 0)
}
}
}
pub fn pos() -> io::Result<(u16, u16)> {
// if we enable raw modes with screen, this could cause problems if raw mode is already enabled in application.
// I am not completely happy with this approach so feel free to find an other way.
unsafe {
if !unix::RAW_MODE_ENABLED_BY_USER || !unix::RAW_MODE_ENABLED_BY_SYSTEM {
// set this boolean so that we know that the systems has enabled raw mode.
unix::RAW_MODE_ENABLED_BY_SYSTEM = true;
unix::into_raw_mode()?;
}
}
unix::into_raw_mode()?;
let pos = pos_raw();
unix::disable_raw_mode()?;
pos
}
pub fn pos_raw() -> io::Result<(u16, u16)> {
// Where is the cursor?
// Use `ESC [ 6 n`.
let mut stdout = io::stdout();
@ -69,21 +73,10 @@ pub fn pos() -> io::Result<(u16, u16)> {
let (cols, c) = read_num()?;
// Expect `R`
let res = if c == 'R' {
if c == 'R' {
// subtract one to get 0-based coords
Ok(((cols - 1) as u16, (rows - 1) as u16))
} else {
return Err(Error::new(ErrorKind::Other, "test"));
};
// If raw mode is enabled from else where in the application (by the user) we do not want to disable raw modes.
// I am not completely happy with this approach so feel free to find an other way.
unsafe {
if unix::RAW_MODE_ENABLED_BY_SYSTEM && !unix::RAW_MODE_ENABLED_BY_USER {
unix::RAW_MODE_ENABLED_BY_SYSTEM = false;
unix::disable_raw_mode()?;
}
Err(Error::new(ErrorKind::Other, "test"))
}
res
}

View File

@ -19,5 +19,5 @@ crossterm_winapi = "0.1.2"
libc = "0.2.51"
[dependencies]
crossterm_utils = "0.2.1"
crossterm_screen = "0.2.1"
crossterm_utils = {path = "../crossterm_utils"}
crossterm_screen = {path = "../crossterm_screen"}

View File

@ -128,7 +128,7 @@ impl Iterator for SyncReader {
},
Ok(2) => {
let option_iter = &mut Some(buf[1]).into_iter();
let mut iter = option_iter.map(|c| Ok(c)).chain(source.bytes());
let iter = option_iter.map(|c| Ok(c)).chain(source.bytes());
if let Ok(e) = parse_event(buf[0], &mut iter.flatten()) {
self.leftover = option_iter.next();
Some(e)

View File

@ -1,4 +1,3 @@
use crossterm_utils::sys::unix;
use std::fs;
use std::io;
use std::os::unix::io::AsRawFd;

View File

@ -12,7 +12,7 @@ readme = "README.md"
edition = "2018"
[dependencies]
crossterm_utils = "0.2.1"
crossterm_utils = {path = "../crossterm_utils"}
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.7", features = ["minwindef", "wincon"] }

View File

@ -24,7 +24,7 @@ pub struct AlternateScreen {
command: Box<(dyn IAlternateScreenCommand + Sync + Send)>,
#[cfg(unix)]
command: sys::ToAlternateScreenCommand,
raw_screen: Option<RawScreen>,
_raw_screen: Option<RawScreen>,
}
impl AlternateScreen {
@ -56,13 +56,13 @@ impl AlternateScreen {
let raw_screen = RawScreen::into_raw_mode()?;
return Ok(AlternateScreen {
command,
raw_screen: Some(raw_screen),
_raw_screen: Some(raw_screen),
});
}
Ok(AlternateScreen {
command,
raw_screen: None,
_raw_screen: None,
})
}

View File

@ -5,8 +5,7 @@ pub use libc::{c_int, termios as Termios};
use std::{io, mem};
static mut ORIGINAL_TERMINAL_MODE: Option<Termios> = None;
pub static mut RAW_MODE_ENABLED_BY_SYSTEM: bool = false;
pub static mut RAW_MODE_ENABLED_BY_USER: bool = false;
pub static mut RAW_MODE_ENABLED: bool = false;
fn unwrap(t: i32) -> io::Result<()> {
if t == -1 {
@ -48,10 +47,11 @@ pub fn into_raw_mode() -> io::Result<()> {
unsafe {
if ORIGINAL_TERMINAL_MODE.is_none() {
ORIGINAL_TERMINAL_MODE = Some(prev_ios.clone())
ORIGINAL_TERMINAL_MODE = Some(prev_ios.clone());
}
}
RAW_MODE_ENABLED = true;
}
raw_terminal_attr(&mut ios);
set_terminal_attr(&ios)?;
Ok(())
@ -61,6 +61,8 @@ pub fn disable_raw_mode() -> io::Result<()> {
unsafe {
if ORIGINAL_TERMINAL_MODE.is_some() {
set_terminal_attr(&ORIGINAL_TERMINAL_MODE.unwrap())?;
RAW_MODE_ENABLED = false;
}
}
Ok(())

View File

@ -1,76 +1,20 @@
extern crate crossterm;
//use crossterm::{Color, Crossterm};
use crossterm::{
AlternateScreen, Attribute, ClearType, Crossterm, InputEvent, KeyEvent, Styler, TerminalCursor,
};
use std::io::Write;
use std::{io, thread, time};
fn run() -> io::Result<()> {
let alternate_screen = AlternateScreen::to_alternate(true)?;
let crossterm = crossterm::Crossterm::new();
let input = crossterm.input();
let mut crossterm_events = input.read_sync();
loop {
if let Some(event) = crossterm_events.next() {
let terminal = crossterm.terminal();
let cursor = crossterm.cursor();
cursor.goto(1, 1)?;
terminal.clear(ClearType::UntilNewLine)?;
if let InputEvent::Keyboard(key) = &event {
match key {
KeyEvent::Ctrl('q') => {
println!("quitting...");
::std::io::stdout().flush();
break;
}
_ => {
let s = "event";
println!(
" {}{}{} : {:?}",
Attribute::Bold,
s,
Attribute::Reset,
event
);
}
}
} else {
println!("disregarding unrelevant event: {:?}", event);
}
}
}
thread::sleep(time::Duration::from_secs(1));
Ok(())
}
fn main() {
match run() {
Ok(_) => {
println!("ok");
}
Err(e) => {
println!("error {:?}", e);
}
}
}
use crossterm::{Color, Crossterm};
// use the `Crossterm` to get an instance to the cursor module | demonstration.
//pub fn main() {
// // Create the crossterm type to access different modules.
// let crossterm = Crossterm::new();
//
// // pass a reference to the current screen.
// let cursor = crossterm.cursor();
// let color = crossterm.color();
// let terminal = crossterm.terminal();
// let terminal = crossterm.input();
// let style = crossterm
// .style("Black font on green background")
// .with(Color::Black)
// .on(Color::Green);
//
// // TODO: perform some actions with the instances above.
//}
pub fn main() {
// Create the crossterm type to access different modules.
let crossterm = Crossterm::new();
// pass a reference to the current screen.
let cursor = crossterm.cursor();
let color = crossterm.color();
let terminal = crossterm.terminal();
let terminal = crossterm.input();
let style = crossterm
.style("Black font on green background")
.with(Color::Black)
.on(Color::Green);
// TODO: perform some actions with the instances above.
}

View File

@ -92,5 +92,5 @@ pub fn blink_cursor() {
}
fn main() {
save_and_reset_position().unwrap();
pos()
}