Raw Screen Cursor Position UNIX Bug Fix (#134)
This commit is contained in:
parent
d31d712a38
commit
0bfebb338d
10
Cargo.toml
10
Cargo.toml
@ -32,12 +32,12 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm_screen = { optional = true, version = "0.2.1" }
|
crossterm_screen = { optional = true, path = "./crossterm_screen" }
|
||||||
crossterm_cursor = { optional = true, version = "0.2.1" }
|
crossterm_cursor = { optional = true, path = "./crossterm_cursor" }
|
||||||
crossterm_terminal = { optional = true, version = "0.2.2" }
|
crossterm_terminal = { optional = true, version = "0.2.2" }
|
||||||
crossterm_style = { optional = true, version = "0.3.1" }
|
crossterm_style = { optional = true, path = "./crossterm_style" }
|
||||||
crossterm_input = { optional = true, version = "0.3.3" }
|
crossterm_input = { optional = true, path = "./crossterm_input" }
|
||||||
crossterm_utils = { optional = false, version = "0.2.1" }
|
crossterm_utils = { optional = false, path = "./crossterm_utils" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "crossterm"
|
name = "crossterm"
|
||||||
|
@ -16,4 +16,4 @@ winapi = { version = "0.3.7", features = ["wincon","winnt","minwindef"] }
|
|||||||
crossterm_winapi = "0.1.2"
|
crossterm_winapi = "0.1.2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm_utils = "0.2.1"
|
crossterm_utils = { path = "../crossterm_utils" }
|
@ -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};
|
use std::io::{self, Error, ErrorKind, Read, Write};
|
||||||
|
|
||||||
/// Get the cursor position based on the current platform.
|
/// Get the cursor position based on the current platform.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn get_cursor_position() -> (u16, u16) {
|
pub fn get_cursor_position() -> (u16, u16) {
|
||||||
|
if unsafe { RAW_MODE_ENABLED } {
|
||||||
|
if let Ok(pos) = pos_raw() {
|
||||||
|
pos
|
||||||
|
} else {
|
||||||
|
(0, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if let Ok(pos) = pos() {
|
if let Ok(pos) = pos() {
|
||||||
pos
|
pos
|
||||||
} else {
|
} else {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pos() -> io::Result<(u16, u16)> {
|
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?
|
// Where is the cursor?
|
||||||
// Use `ESC [ 6 n`.
|
// Use `ESC [ 6 n`.
|
||||||
let mut stdout = io::stdout();
|
let mut stdout = io::stdout();
|
||||||
@ -69,21 +73,10 @@ pub fn pos() -> io::Result<(u16, u16)> {
|
|||||||
let (cols, c) = read_num()?;
|
let (cols, c) = read_num()?;
|
||||||
|
|
||||||
// Expect `R`
|
// Expect `R`
|
||||||
let res = if c == 'R' {
|
if c == 'R' {
|
||||||
// subtract one to get 0-based coords
|
// subtract one to get 0-based coords
|
||||||
Ok(((cols - 1) as u16, (rows - 1) as u16))
|
Ok(((cols - 1) as u16, (rows - 1) as u16))
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::new(ErrorKind::Other, "test"));
|
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()?;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
@ -19,5 +19,5 @@ crossterm_winapi = "0.1.2"
|
|||||||
libc = "0.2.51"
|
libc = "0.2.51"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm_utils = "0.2.1"
|
crossterm_utils = {path = "../crossterm_utils"}
|
||||||
crossterm_screen = "0.2.1"
|
crossterm_screen = {path = "../crossterm_screen"}
|
@ -128,7 +128,7 @@ impl Iterator for SyncReader {
|
|||||||
},
|
},
|
||||||
Ok(2) => {
|
Ok(2) => {
|
||||||
let option_iter = &mut Some(buf[1]).into_iter();
|
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()) {
|
if let Ok(e) = parse_event(buf[0], &mut iter.flatten()) {
|
||||||
self.leftover = option_iter.next();
|
self.leftover = option_iter.next();
|
||||||
Some(e)
|
Some(e)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crossterm_utils::sys::unix;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
@ -12,7 +12,7 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm_utils = "0.2.1"
|
crossterm_utils = {path = "../crossterm_utils"}
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3.7", features = ["minwindef", "wincon"] }
|
winapi = { version = "0.3.7", features = ["minwindef", "wincon"] }
|
||||||
|
@ -24,7 +24,7 @@ pub struct AlternateScreen {
|
|||||||
command: Box<(dyn IAlternateScreenCommand + Sync + Send)>,
|
command: Box<(dyn IAlternateScreenCommand + Sync + Send)>,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
command: sys::ToAlternateScreenCommand,
|
command: sys::ToAlternateScreenCommand,
|
||||||
raw_screen: Option<RawScreen>,
|
_raw_screen: Option<RawScreen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlternateScreen {
|
impl AlternateScreen {
|
||||||
@ -56,13 +56,13 @@ impl AlternateScreen {
|
|||||||
let raw_screen = RawScreen::into_raw_mode()?;
|
let raw_screen = RawScreen::into_raw_mode()?;
|
||||||
return Ok(AlternateScreen {
|
return Ok(AlternateScreen {
|
||||||
command,
|
command,
|
||||||
raw_screen: Some(raw_screen),
|
_raw_screen: Some(raw_screen),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(AlternateScreen {
|
Ok(AlternateScreen {
|
||||||
command,
|
command,
|
||||||
raw_screen: None,
|
_raw_screen: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,7 @@ pub use libc::{c_int, termios as Termios};
|
|||||||
use std::{io, mem};
|
use std::{io, mem};
|
||||||
|
|
||||||
static mut ORIGINAL_TERMINAL_MODE: Option<Termios> = None;
|
static mut ORIGINAL_TERMINAL_MODE: Option<Termios> = None;
|
||||||
pub static mut RAW_MODE_ENABLED_BY_SYSTEM: bool = false;
|
pub static mut RAW_MODE_ENABLED: bool = false;
|
||||||
pub static mut RAW_MODE_ENABLED_BY_USER: bool = false;
|
|
||||||
|
|
||||||
fn unwrap(t: i32) -> io::Result<()> {
|
fn unwrap(t: i32) -> io::Result<()> {
|
||||||
if t == -1 {
|
if t == -1 {
|
||||||
@ -48,10 +47,11 @@ pub fn into_raw_mode() -> io::Result<()> {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ORIGINAL_TERMINAL_MODE.is_none() {
|
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);
|
raw_terminal_attr(&mut ios);
|
||||||
set_terminal_attr(&ios)?;
|
set_terminal_attr(&ios)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -61,6 +61,8 @@ pub fn disable_raw_mode() -> io::Result<()> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
if ORIGINAL_TERMINAL_MODE.is_some() {
|
if ORIGINAL_TERMINAL_MODE.is_some() {
|
||||||
set_terminal_attr(&ORIGINAL_TERMINAL_MODE.unwrap())?;
|
set_terminal_attr(&ORIGINAL_TERMINAL_MODE.unwrap())?;
|
||||||
|
|
||||||
|
RAW_MODE_ENABLED = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,76 +1,20 @@
|
|||||||
extern crate crossterm;
|
extern crate crossterm;
|
||||||
|
|
||||||
//use crossterm::{Color, 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 the `Crossterm` to get an instance to the cursor module | demonstration.
|
// use the `Crossterm` to get an instance to the cursor module | demonstration.
|
||||||
//pub fn main() {
|
pub fn main() {
|
||||||
// // Create the crossterm type to access different modules.
|
// Create the crossterm type to access different modules.
|
||||||
// let crossterm = Crossterm::new();
|
let crossterm = Crossterm::new();
|
||||||
//
|
|
||||||
// // pass a reference to the current screen.
|
// pass a reference to the current screen.
|
||||||
// let cursor = crossterm.cursor();
|
let cursor = crossterm.cursor();
|
||||||
// let color = crossterm.color();
|
let color = crossterm.color();
|
||||||
// let terminal = crossterm.terminal();
|
let terminal = crossterm.terminal();
|
||||||
// let terminal = crossterm.input();
|
let terminal = crossterm.input();
|
||||||
// let style = crossterm
|
let style = crossterm
|
||||||
// .style("Black font on green background")
|
.style("Black font on green background")
|
||||||
// .with(Color::Black)
|
.with(Color::Black)
|
||||||
// .on(Color::Green);
|
.on(Color::Green);
|
||||||
//
|
|
||||||
// // TODO: perform some actions with the instances above.
|
// TODO: perform some actions with the instances above.
|
||||||
//}
|
}
|
||||||
|
@ -92,5 +92,5 @@ pub fn blink_cursor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
save_and_reset_position().unwrap();
|
pos()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user