Make the events module an optional feature (#776)
This commit is contained in:
parent
b354b4cc34
commit
03c25178af
4
.github/workflows/crossterm_test.yml
vendored
4
.github/workflows/crossterm_test.yml
vendored
@ -57,7 +57,7 @@ jobs:
|
||||
run: cargo test --lib --features serde -- --nocapture --test-threads 1
|
||||
continue-on-error: ${{ matrix.can-fail }}
|
||||
- name: Test event-stream feature
|
||||
run: cargo test --lib --features event-stream -- --nocapture --test-threads 1
|
||||
run: cargo test --lib --features "event-stream,events" -- --nocapture --test-threads 1
|
||||
continue-on-error: ${{ matrix.can-fail }}
|
||||
- name: Test all features
|
||||
run: cargo test --all-features -- --nocapture --test-threads 1
|
||||
@ -68,7 +68,7 @@ jobs:
|
||||
continue-on-error: ${{ matrix.can-fail }}
|
||||
- name: Test no default features with windows feature enabled
|
||||
if: matrix.os == 'windows-2019'
|
||||
run: cargo test --no-default-features --features windows -- --nocapture --test-threads 1
|
||||
run: cargo test --no-default-features --features "windows" -- --nocapture --test-threads 1
|
||||
- name: Test Packaging
|
||||
if: matrix.rust == 'stable'
|
||||
run: cargo package
|
||||
|
34
Cargo.toml
34
Cargo.toml
@ -26,12 +26,12 @@ all-features = true
|
||||
# Features
|
||||
#
|
||||
[features]
|
||||
default = ["bracketed-paste", "windows"]
|
||||
default = ["bracketed-paste", "windows", "events"]
|
||||
windows = ["winapi", "crossterm_winapi"]
|
||||
bracketed-paste = []
|
||||
event-stream = ["futures-core"]
|
||||
event-stream = ["futures-core", "events"]
|
||||
use-dev-tty = ["filedescriptor"]
|
||||
|
||||
events = ["mio", "signal-hook", "signal-hook-mio"]
|
||||
#
|
||||
# Shared dependencies
|
||||
#
|
||||
@ -59,10 +59,10 @@ crossterm_winapi = { version = "0.9", optional = true }
|
||||
#
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
signal-hook = { version = "0.3.13" }
|
||||
signal-hook = { version = "0.3.13", optional = true }
|
||||
filedescriptor = { version = "0.8", optional = true }
|
||||
mio = { version = "0.8", features = ["os-poll"] }
|
||||
signal-hook-mio = { version = "0.2.3", features = ["support-v0_8"] }
|
||||
mio = { version = "0.8", features = ["os-poll"], optional = true }
|
||||
signal-hook-mio = { version = "0.2.3", features = ["support-v0_8"], optional = true }
|
||||
|
||||
#
|
||||
# Dev dependencies (examples, ...)
|
||||
@ -79,12 +79,28 @@ serde_json = "1.0"
|
||||
#
|
||||
[[example]]
|
||||
name = "event-read"
|
||||
required-features = ["bracketed-paste"]
|
||||
required-features = ["bracketed-paste", "events"]
|
||||
|
||||
[[example]]
|
||||
name = "event-match-modifiers"
|
||||
required-features = ["bracketed-paste", "events"]
|
||||
|
||||
[[example]]
|
||||
name = "event-poll-read"
|
||||
required-features = ["bracketed-paste", "events"]
|
||||
|
||||
[[example]]
|
||||
name = "event-stream-async-std"
|
||||
required-features = ["event-stream"]
|
||||
required-features = ["event-stream", "events"]
|
||||
|
||||
[[example]]
|
||||
name = "event-stream-tokio"
|
||||
required-features = ["event-stream"]
|
||||
required-features = ["event-stream", "events"]
|
||||
|
||||
[[example]]
|
||||
name = "event-read-char-line"
|
||||
required-features = ["events"]
|
||||
|
||||
[[example]]
|
||||
name = "stderr"
|
||||
required-features = ["events"]
|
||||
|
12
README.md
12
README.md
@ -144,6 +144,12 @@ features = ["event-stream"]
|
||||
|:---------------|:---------------------------------------------|
|
||||
| `event-stream` | `futures::Stream` producing `Result<Event>`. |
|
||||
| `serde` | (De)serializing of events. |
|
||||
| `events` | Reading input/system events (enabled by default) |
|
||||
| `filedescriptor` | Use raw filedescriptor for all events rather then mio dependency |
|
||||
|
||||
|
||||
To use crossterm as a very tin layer you can disable the `events` feature or use `filedescriptor` feature.
|
||||
This can disable `mio` / `signal-hook` / `signal-hook-mio` dependencies.
|
||||
|
||||
### Dependency Justification
|
||||
|
||||
@ -151,9 +157,9 @@ features = ["event-stream"]
|
||||
|:---------------|:---------------------------------------------------------------------------------|:--------------------------------------|
|
||||
| `bitflags` | `KeyModifiers`, those are differ based on input. | always |
|
||||
| `parking_lot` | locking `RwLock`s with a timeout, const mutexes. | always |
|
||||
| `libc` | UNIX terminal_size/raw modes/set_title and several other low level functionality. | UNIX only |
|
||||
| `Mio` | event readiness polling, waking up poller | UNIX only |
|
||||
| `signal-hook` | signal-hook is used to handle terminal resize SIGNAL with Mio. | UNIX only |
|
||||
| `libc` | UNIX terminal_size/raw modes/set_title and several other low level functionality. | optional (`events` feature), UNIX only |
|
||||
| `Mio` | event readiness polling, waking up poller | optional (`events` feature), UNIX only |
|
||||
| `signal-hook` | signal-hook is used to handle terminal resize SIGNAL with Mio. | optional (`events` feature),UNIX only |
|
||||
| `winapi` | Used for low-level windows system calls which ANSI codes can't replace | windows only |
|
||||
| `futures-core` | For async stream of events | only with `event-stream` feature flag |
|
||||
| `serde` | ***ser***ializing and ***de***serializing of events | only with `serde` feature flag |
|
||||
|
@ -48,10 +48,11 @@ use std::fmt;
|
||||
use crate::Result;
|
||||
use crate::{csi, impl_display, Command};
|
||||
|
||||
pub use sys::position;
|
||||
|
||||
pub(crate) mod sys;
|
||||
|
||||
#[cfg(feature = "events")]
|
||||
pub use sys::position;
|
||||
|
||||
/// A command that moves the terminal cursor to the given position (column, row).
|
||||
///
|
||||
/// # Notes
|
||||
@ -426,13 +427,14 @@ impl_display!(for DisableBlinking);
|
||||
impl_display!(for SetCursorStyle);
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "events")]
|
||||
mod tests {
|
||||
use std::io::{self, stdout};
|
||||
|
||||
use crate::execute;
|
||||
|
||||
use super::{
|
||||
position, MoveDown, MoveLeft, MoveRight, MoveTo, MoveUp, RestorePosition, SavePosition,
|
||||
sys::position, MoveDown, MoveLeft, MoveRight, MoveTo, MoveUp, RestorePosition, SavePosition,
|
||||
};
|
||||
|
||||
// Test is disabled, because it's failing on Travis
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! This module provides platform related functions.
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(feature = "events")]
|
||||
pub use self::unix::position;
|
||||
#[cfg(windows)]
|
||||
pub use self::windows::position;
|
||||
@ -14,4 +15,5 @@ pub(crate) use self::windows::{
|
||||
pub(crate) mod windows;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(feature = "events")]
|
||||
pub(crate) mod unix;
|
||||
|
269
src/event.rs
269
src/event.rs
@ -80,37 +80,38 @@
|
||||
//! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of
|
||||
//! them (`event-*`).
|
||||
|
||||
pub(crate) mod filter;
|
||||
pub(crate) mod read;
|
||||
pub(crate) mod source;
|
||||
#[cfg(feature = "event-stream")]
|
||||
pub(crate) mod stream;
|
||||
pub(crate) mod sys;
|
||||
pub(crate) mod timeout;
|
||||
|
||||
#[cfg(feature = "event-stream")]
|
||||
pub use stream::EventStream;
|
||||
|
||||
use crate::event::{
|
||||
filter::{EventFilter, Filter},
|
||||
read::InternalEventReader,
|
||||
timeout::PollTimeout,
|
||||
};
|
||||
use crate::{csi, Command};
|
||||
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(windows)]
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{csi, Command, Result};
|
||||
use filter::{EventFilter, Filter};
|
||||
use read::InternalEventReader;
|
||||
#[cfg(feature = "event-stream")]
|
||||
pub use stream::EventStream;
|
||||
use timeout::PollTimeout;
|
||||
|
||||
pub(crate) mod filter;
|
||||
mod read;
|
||||
mod source;
|
||||
#[cfg(feature = "event-stream")]
|
||||
mod stream;
|
||||
pub(crate) mod sys;
|
||||
mod timeout;
|
||||
use bitflags::bitflags;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// Static instance of `InternalEventReader`.
|
||||
/// This needs to be static because there can be one event reader.
|
||||
static INTERNAL_EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None);
|
||||
|
||||
fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
|
||||
pub(crate) fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
|
||||
MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
|
||||
reader.get_or_insert_with(InternalEventReader::default)
|
||||
})
|
||||
@ -164,7 +165,7 @@ fn try_lock_internal_event_reader_for(
|
||||
/// poll(Duration::from_millis(100))
|
||||
/// }
|
||||
/// ```
|
||||
pub fn poll(timeout: Duration) -> Result<bool> {
|
||||
pub fn poll(timeout: Duration) -> crate::Result<bool> {
|
||||
poll_internal(Some(timeout), &EventFilter)
|
||||
}
|
||||
|
||||
@ -207,7 +208,7 @@ pub fn poll(timeout: Duration) -> Result<bool> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn read() -> Result<Event> {
|
||||
pub fn read() -> crate::Result<Event> {
|
||||
match read_internal(&EventFilter)? {
|
||||
InternalEvent::Event(event) => Ok(event),
|
||||
#[cfg(unix)]
|
||||
@ -216,7 +217,7 @@ pub fn read() -> Result<Event> {
|
||||
}
|
||||
|
||||
/// Polls to check if there are any `InternalEvent`s that can be read within the given duration.
|
||||
pub(crate) fn poll_internal<F>(timeout: Option<Duration>, filter: &F) -> Result<bool>
|
||||
pub(crate) fn poll_internal<F>(timeout: Option<Duration>, filter: &F) -> crate::Result<bool>
|
||||
where
|
||||
F: Filter,
|
||||
{
|
||||
@ -234,7 +235,7 @@ where
|
||||
}
|
||||
|
||||
/// Reads a single `InternalEvent`.
|
||||
pub(crate) fn read_internal<F>(filter: &F) -> Result<InternalEvent>
|
||||
pub(crate) fn read_internal<F>(filter: &F) -> crate::Result<InternalEvent>
|
||||
where
|
||||
F: Filter,
|
||||
{
|
||||
@ -242,12 +243,42 @@ where
|
||||
reader.read(filter)
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Represents special flags that tell compatible terminals to add extra information to keyboard events.
|
||||
///
|
||||
/// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information.
|
||||
///
|
||||
/// Alternate keys and Unicode codepoints are not yet supported by crossterm.
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct KeyboardEnhancementFlags: u8 {
|
||||
/// Represent Escape and modified keys using CSI-u sequences, so they can be unambiguously
|
||||
/// read.
|
||||
const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001;
|
||||
/// Add extra events with [`KeyEvent.kind`] set to [`KeyEventKind::Repeat`] or
|
||||
/// [`KeyEventKind::Release`] when keys are autorepeated or released.
|
||||
const REPORT_EVENT_TYPES = 0b0000_0010;
|
||||
// Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes)
|
||||
// in addition to the base keycode. The alternate keycode overrides the base keycode in
|
||||
// resulting `KeyEvent`s.
|
||||
const REPORT_ALTERNATE_KEYS = 0b0000_0100;
|
||||
/// Represent all keyboard events as CSI-u sequences. This is required to get repeat/release
|
||||
/// events for plain-text keys.
|
||||
const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 0b0000_1000;
|
||||
// Send the Unicode codepoint as well as the keycode.
|
||||
//
|
||||
// *Note*: this is not yet supported by crossterm.
|
||||
// const REPORT_ASSOCIATED_TEXT = 0b0001_0000;
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that enables mouse event capturing.
|
||||
///
|
||||
/// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
|
||||
#[cfg(feature = "events")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct EnableMouseCapture;
|
||||
|
||||
#[cfg(feature = "events")]
|
||||
impl Command for EnableMouseCapture {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(concat!(
|
||||
@ -265,7 +296,7 @@ impl Command for EnableMouseCapture {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
sys::windows::enable_mouse_capture()
|
||||
}
|
||||
|
||||
@ -294,7 +325,7 @@ impl Command for DisableMouseCapture {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
sys::windows::disable_mouse_capture()
|
||||
}
|
||||
|
||||
@ -304,31 +335,81 @@ impl Command for DisableMouseCapture {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Represents special flags that tell compatible terminals to add extra information to keyboard events.
|
||||
///
|
||||
/// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information.
|
||||
///
|
||||
/// Alternate keys and Unicode codepoints are not yet supported by crossterm.
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct KeyboardEnhancementFlags: u8 {
|
||||
/// Represent Escape and modified keys using CSI-u sequences, so they can be unambiguously
|
||||
/// read.
|
||||
const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001;
|
||||
/// Add extra events with [`KeyEvent.kind`] set to [`KeyEventKind::Repeat`] or
|
||||
/// [`KeyEventKind::Release`] when keys are autorepeated or released.
|
||||
const REPORT_EVENT_TYPES = 0b0000_0010;
|
||||
// Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes)
|
||||
// in addition to the base keycode. The alternate keycode overrides the base keycode in
|
||||
// resulting `KeyEvent`s.
|
||||
const REPORT_ALTERNATE_KEYS = 0b0000_0100;
|
||||
/// Represent all keyboard events as CSI-u sequences. This is required to get repeat/release
|
||||
/// events for plain-text keys.
|
||||
const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 0b0000_1000;
|
||||
// Send the Unicode codepoint as well as the keycode.
|
||||
//
|
||||
// *Note*: this is not yet supported by crossterm.
|
||||
// const REPORT_ASSOCIATED_TEXT = 0b0001_0000;
|
||||
/// A command that enables focus event emission.
|
||||
///
|
||||
/// It should be paired with [`DisableFocusChange`] at the end of execution.
|
||||
///
|
||||
/// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct EnableFocusChange;
|
||||
|
||||
impl Command for EnableFocusChange {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?1004h"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
// Focus events are always enabled on Windows
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that disables focus event emission.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DisableFocusChange;
|
||||
|
||||
impl Command for DisableFocusChange {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?1004l"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
// Focus events can't be disabled on Windows
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that enables [bracketed paste mode](https://en.wikipedia.org/wiki/Bracketed-paste).
|
||||
///
|
||||
/// It should be paired with [`DisableBracketedPaste`] at the end of execution.
|
||||
///
|
||||
/// This is not supported in older Windows terminals without
|
||||
/// [virtual terminal sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct EnableBracketedPaste;
|
||||
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
impl Command for EnableBracketedPaste {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?2004h"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Unsupported,
|
||||
"Bracketed paste not implemented in the legacy Windows API.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that disables bracketed paste mode.
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DisableBracketedPaste;
|
||||
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
impl Command for DisableBracketedPaste {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?2004l"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,7 +458,9 @@ impl Command for PushKeyboardEnhancementFlags {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
use std::io;
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Keyboard progressive enhancement not implemented for the legacy Windows API.",
|
||||
@ -404,7 +487,9 @@ impl Command for PopKeyboardEnhancementFlags {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
fn execute_winapi(&self) -> crate::Result<()> {
|
||||
use std::io;
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Keyboard progressive enhancement not implemented for the legacy Windows API.",
|
||||
@ -417,84 +502,6 @@ impl Command for PopKeyboardEnhancementFlags {
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that enables focus event emission.
|
||||
///
|
||||
/// It should be paired with [`DisableFocusChange`] at the end of execution.
|
||||
///
|
||||
/// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct EnableFocusChange;
|
||||
|
||||
impl Command for EnableFocusChange {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?1004h"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
// Focus events are always enabled on Windows
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that disables focus event emission.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DisableFocusChange;
|
||||
|
||||
impl Command for DisableFocusChange {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?1004l"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
// Focus events can't be disabled on Windows
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that enables [bracketed paste mode](https://en.wikipedia.org/wiki/Bracketed-paste).
|
||||
///
|
||||
/// It should be paired with [`DisableBracketedPaste`] at the end of execution.
|
||||
///
|
||||
/// This is not supported in older Windows terminals without
|
||||
/// [virtual terminal sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct EnableBracketedPaste;
|
||||
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
impl Command for EnableBracketedPaste {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?2004h"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Bracketed paste not implemented in the legacy Windows API.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A command that disables bracketed paste mode.
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DisableBracketedPaste;
|
||||
|
||||
#[cfg(feature = "bracketed-paste")]
|
||||
impl Command for DisableBracketedPaste {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
f.write_str(csi!("?2004l"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an event.
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))]
|
||||
|
@ -1,12 +1,14 @@
|
||||
use std::{collections::vec_deque::VecDeque, io, time::Duration};
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::source::unix::UnixInternalEventSource;
|
||||
use crate::event::source::unix::UnixInternalEventSource;
|
||||
#[cfg(windows)]
|
||||
use super::source::windows::WindowsEventSource;
|
||||
use crate::event::source::windows::WindowsEventSource;
|
||||
#[cfg(feature = "event-stream")]
|
||||
use super::sys::Waker;
|
||||
use super::{filter::Filter, source::EventSource, timeout::PollTimeout, InternalEvent, Result};
|
||||
use crate::event::sys::Waker;
|
||||
use crate::event::{filter::Filter, source::EventSource, timeout::PollTimeout, InternalEvent};
|
||||
use crate::Result;
|
||||
|
||||
/// Can be used to read `InternalEvent`s.
|
||||
pub(crate) struct InternalEventReader {
|
||||
events: VecDeque<InternalEvent>,
|
||||
|
@ -8,14 +8,9 @@ use crate::Result;
|
||||
#[cfg(feature = "event-stream")]
|
||||
use crate::event::sys::Waker;
|
||||
use crate::event::{
|
||||
source::EventSource,
|
||||
sys::unix::{
|
||||
file_descriptor::{tty_fd, FileDesc},
|
||||
parse::parse_event,
|
||||
},
|
||||
timeout::PollTimeout,
|
||||
Event, InternalEvent,
|
||||
source::EventSource, sys::unix::parse::parse_event, timeout::PollTimeout, Event, InternalEvent,
|
||||
};
|
||||
use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};
|
||||
|
||||
// Tokens to identify file descriptor
|
||||
const TTY_TOKEN: Token = Token(0);
|
||||
|
@ -11,15 +11,8 @@ use filedescriptor::{poll, pollfd, POLLIN};
|
||||
|
||||
#[cfg(feature = "event-stream")]
|
||||
use crate::event::sys::Waker;
|
||||
|
||||
use crate::event::{
|
||||
source::EventSource,
|
||||
sys::unix::{
|
||||
file_descriptor::{tty_fd, FileDesc},
|
||||
parse::parse_event,
|
||||
},
|
||||
InternalEvent,
|
||||
};
|
||||
use crate::event::{source::EventSource, sys::unix::parse::parse_event, InternalEvent};
|
||||
use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};
|
||||
|
||||
/// Holds a prototypical Waker and a receiver we can wait on when doing select().
|
||||
#[cfg(feature = "event-stream")]
|
||||
|
@ -8,12 +8,12 @@ use crate::event::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "event-stream")]
|
||||
use super::super::sys::Waker;
|
||||
use super::super::{
|
||||
use crate::event::sys::Waker;
|
||||
use crate::event::{
|
||||
source::EventSource,
|
||||
sys::windows::parse::{handle_key_event, handle_mouse_event},
|
||||
timeout::PollTimeout,
|
||||
InternalEvent, Result,
|
||||
InternalEvent,
|
||||
};
|
||||
|
||||
pub(crate) struct WindowsEventSource {
|
||||
@ -24,7 +24,7 @@ pub(crate) struct WindowsEventSource {
|
||||
}
|
||||
|
||||
impl WindowsEventSource {
|
||||
pub(crate) fn new() -> Result<WindowsEventSource> {
|
||||
pub(crate) fn new() -> crate::Result<WindowsEventSource> {
|
||||
let console = Console::from(Handle::current_in_handle()?);
|
||||
Ok(WindowsEventSource {
|
||||
console,
|
||||
@ -41,7 +41,7 @@ impl WindowsEventSource {
|
||||
}
|
||||
|
||||
impl EventSource for WindowsEventSource {
|
||||
fn try_read(&mut self, timeout: Option<Duration>) -> Result<Option<InternalEvent>> {
|
||||
fn try_read(&mut self, timeout: Option<Duration>) -> crate::Result<Option<InternalEvent>> {
|
||||
let poll_timeout = PollTimeout::new(timeout);
|
||||
|
||||
loop {
|
||||
|
@ -14,7 +14,7 @@ use futures_core::stream::Stream;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
use super::{
|
||||
use crate::event::{
|
||||
filter::EventFilter, lock_internal_event_reader, poll_internal, read_internal, sys::Waker,
|
||||
Event, InternalEvent,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
#[cfg(feature = "event-stream")]
|
||||
pub(crate) mod waker;
|
||||
|
||||
pub(crate) mod file_descriptor;
|
||||
#[cfg(feature = "events")]
|
||||
pub(crate) mod parse;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use mio::{Registry, Token};
|
||||
use ::mio::{Registry, Token};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
@ -8,7 +8,7 @@ use crate::Result;
|
||||
/// This type wraps `mio::Waker`, for more information see its documentation.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Waker {
|
||||
inner: Arc<Mutex<mio::Waker>>,
|
||||
inner: Arc<Mutex<::mio::Waker>>,
|
||||
}
|
||||
|
||||
impl Waker {
|
||||
|
@ -8,11 +8,10 @@ use crossterm_winapi::{ConsoleMode, Handle};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
#[cfg(feature = "event-stream")]
|
||||
pub(crate) mod waker;
|
||||
|
||||
pub(crate) mod parse;
|
||||
pub(crate) mod poll;
|
||||
#[cfg(feature = "event-stream")]
|
||||
pub(crate) mod waker;
|
||||
|
||||
const ENABLE_MOUSE_MODE: u32 = 0x0010 | 0x0080 | 0x0008;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crossterm_winapi::{ControlKeyState, EventFlags, KeyEventRecord, MouseEvent, ScreenBuffer};
|
||||
use crossterm_winapi::{ControlKeyState, EventFlags, KeyEventRecord, ScreenBuffer};
|
||||
use winapi::um::{
|
||||
wincon::{
|
||||
CAPSLOCK_ON, LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED,
|
||||
@ -13,7 +13,10 @@ use winapi::um::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind},
|
||||
event::{
|
||||
Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEvent,
|
||||
MouseEventKind,
|
||||
},
|
||||
Result,
|
||||
};
|
||||
|
||||
@ -25,7 +28,7 @@ pub struct MouseButtonsPressed {
|
||||
}
|
||||
|
||||
pub(crate) fn handle_mouse_event(
|
||||
mouse_event: MouseEvent,
|
||||
mouse_event: crossterm_winapi::MouseEvent,
|
||||
buttons_pressed: &MouseButtonsPressed,
|
||||
) -> Option<Event> {
|
||||
if let Ok(Some(event)) = parse_mouse_event_record(&mouse_event, buttons_pressed) {
|
||||
@ -304,9 +307,9 @@ pub fn parse_relative_y(y: i16) -> Result<i16> {
|
||||
}
|
||||
|
||||
fn parse_mouse_event_record(
|
||||
event: &MouseEvent,
|
||||
event: &crossterm_winapi::MouseEvent,
|
||||
buttons_pressed: &MouseButtonsPressed,
|
||||
) -> Result<Option<crate::event::MouseEvent>> {
|
||||
) -> Result<Option<MouseEvent>> {
|
||||
let modifiers = KeyModifiers::from(&event.control_key_state);
|
||||
|
||||
let xpos = event.mouse_position.x as u16;
|
||||
@ -363,7 +366,7 @@ fn parse_mouse_event_record(
|
||||
_ => None,
|
||||
};
|
||||
|
||||
Ok(kind.map(|kind| crate::event::MouseEvent {
|
||||
Ok(kind.map(|kind| MouseEvent {
|
||||
kind,
|
||||
column: xpos,
|
||||
row: ypos,
|
||||
|
@ -242,6 +242,7 @@ pub use crate::{
|
||||
/// A module to work with the terminal cursor
|
||||
pub mod cursor;
|
||||
/// A module to read events.
|
||||
#[cfg(feature = "events")]
|
||||
pub mod event;
|
||||
/// A module to apply attributes and colors on your text.
|
||||
pub mod style;
|
||||
|
@ -98,6 +98,7 @@ use crate::{csi, impl_display, Result};
|
||||
|
||||
pub(crate) mod sys;
|
||||
|
||||
#[cfg(feature = "events")]
|
||||
pub use sys::supports_keyboard_enhancement;
|
||||
|
||||
/// Tells whether the raw mode is enabled.
|
||||
|
@ -1,10 +1,12 @@
|
||||
//! This module provides platform related functions.
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(feature = "events")]
|
||||
pub use self::unix::supports_keyboard_enhancement;
|
||||
#[cfg(unix)]
|
||||
pub(crate) use self::unix::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled, size};
|
||||
#[cfg(windows)]
|
||||
#[cfg(feature = "events")]
|
||||
pub use self::windows::supports_keyboard_enhancement;
|
||||
#[cfg(windows)]
|
||||
pub(crate) use self::windows::{
|
||||
@ -15,5 +17,7 @@ pub(crate) use self::windows::{
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod file_descriptor;
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
|
@ -1,21 +1,18 @@
|
||||
//! UNIX related logic for terminal manipulation.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::{IntoRawFd, RawFd};
|
||||
use std::time::Duration;
|
||||
use std::{io, mem, process};
|
||||
|
||||
use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};
|
||||
use libc::{
|
||||
cfmakeraw, ioctl, tcgetattr, tcsetattr, termios as Termios, winsize, STDOUT_FILENO, TCSANOW,
|
||||
TIOCGWINSZ,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::fs::File;
|
||||
|
||||
use std::os::unix::io::{IntoRawFd, RawFd};
|
||||
|
||||
use std::{io, mem, process};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::event::filter::{KeyboardEnhancementFlagsFilter, PrimaryDeviceAttributesFilter};
|
||||
use crate::event::sys::unix::file_descriptor::{tty_fd, FileDesc};
|
||||
use crate::event::{poll_internal, read_internal, InternalEvent};
|
||||
|
||||
// Some(Termios) -> we're in the raw mode and this is the previous mode
|
||||
// None -> we're not in the raw mode
|
||||
@ -96,6 +93,7 @@ pub(crate) fn disable_raw_mode() -> Result<()> {
|
||||
///
|
||||
/// On unix systems, this function will block and possibly time out while
|
||||
/// [`crossterm::event::read`](crate::event::read) or [`crossterm::event::poll`](crate::event::poll) are being called.
|
||||
#[cfg(feature = "events")]
|
||||
pub fn supports_keyboard_enhancement() -> Result<bool> {
|
||||
if is_raw_mode_enabled() {
|
||||
read_supports_keyboard_enhancement_raw()
|
||||
@ -104,6 +102,7 @@ pub fn supports_keyboard_enhancement() -> Result<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "events")]
|
||||
fn read_supports_keyboard_enhancement_flags() -> Result<bool> {
|
||||
enable_raw_mode()?;
|
||||
let flags = read_supports_keyboard_enhancement_raw();
|
||||
@ -111,7 +110,15 @@ fn read_supports_keyboard_enhancement_flags() -> Result<bool> {
|
||||
flags
|
||||
}
|
||||
|
||||
#[cfg(feature = "events")]
|
||||
fn read_supports_keyboard_enhancement_raw() -> Result<bool> {
|
||||
use crate::event::{
|
||||
filter::{KeyboardEnhancementFlagsFilter, PrimaryDeviceAttributesFilter},
|
||||
poll_internal, read_internal, InternalEvent,
|
||||
};
|
||||
use std::io::Write;
|
||||
use std::time::Duration;
|
||||
|
||||
// This is the recommended method for testing support for the keyboard enhancement protocol.
|
||||
// We send a query for the flags supported by the terminal and then the primary device attributes
|
||||
// query. If we receive the primary device attributes response but not the keyboard enhancement
|
||||
|
@ -61,6 +61,7 @@ pub(crate) fn size() -> Result<(u16, u16)> {
|
||||
/// Queries the terminal's support for progressive keyboard enhancement.
|
||||
///
|
||||
/// This always returns `Ok(false)` on Windows.
|
||||
#[cfg(feature = "events")]
|
||||
pub fn supports_keyboard_enhancement() -> Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user