Make the events module an optional feature (#776)

This commit is contained in:
Timon 2023-04-07 17:09:15 +02:00 committed by GitHub
parent b354b4cc34
commit 03c25178af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 234 additions and 195 deletions

View File

@ -57,7 +57,7 @@ jobs:
run: cargo test --lib --features serde -- --nocapture --test-threads 1 run: cargo test --lib --features serde -- --nocapture --test-threads 1
continue-on-error: ${{ matrix.can-fail }} continue-on-error: ${{ matrix.can-fail }}
- name: Test event-stream feature - 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 }} continue-on-error: ${{ matrix.can-fail }}
- name: Test all features - name: Test all features
run: cargo test --all-features -- --nocapture --test-threads 1 run: cargo test --all-features -- --nocapture --test-threads 1
@ -68,7 +68,7 @@ jobs:
continue-on-error: ${{ matrix.can-fail }} continue-on-error: ${{ matrix.can-fail }}
- name: Test no default features with windows feature enabled - name: Test no default features with windows feature enabled
if: matrix.os == 'windows-2019' 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 - name: Test Packaging
if: matrix.rust == 'stable' if: matrix.rust == 'stable'
run: cargo package run: cargo package

View File

@ -26,12 +26,12 @@ all-features = true
# Features # Features
# #
[features] [features]
default = ["bracketed-paste", "windows"] default = ["bracketed-paste", "windows", "events"]
windows = ["winapi", "crossterm_winapi"] windows = ["winapi", "crossterm_winapi"]
bracketed-paste = [] bracketed-paste = []
event-stream = ["futures-core"] event-stream = ["futures-core", "events"]
use-dev-tty = ["filedescriptor"] use-dev-tty = ["filedescriptor"]
events = ["mio", "signal-hook", "signal-hook-mio"]
# #
# Shared dependencies # Shared dependencies
# #
@ -59,10 +59,10 @@ crossterm_winapi = { version = "0.9", optional = true }
# #
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
libc = "0.2" libc = "0.2"
signal-hook = { version = "0.3.13" } signal-hook = { version = "0.3.13", optional = true }
filedescriptor = { version = "0.8", optional = true } filedescriptor = { version = "0.8", optional = true }
mio = { version = "0.8", features = ["os-poll"] } mio = { version = "0.8", features = ["os-poll"], optional = true }
signal-hook-mio = { version = "0.2.3", features = ["support-v0_8"] } signal-hook-mio = { version = "0.2.3", features = ["support-v0_8"], optional = true }
# #
# Dev dependencies (examples, ...) # Dev dependencies (examples, ...)
@ -79,12 +79,28 @@ serde_json = "1.0"
# #
[[example]] [[example]]
name = "event-read" 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]] [[example]]
name = "event-stream-async-std" name = "event-stream-async-std"
required-features = ["event-stream"] required-features = ["event-stream", "events"]
[[example]] [[example]]
name = "event-stream-tokio" 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"]

View File

@ -144,6 +144,12 @@ features = ["event-stream"]
|:---------------|:---------------------------------------------| |:---------------|:---------------------------------------------|
| `event-stream` | `futures::Stream` producing `Result<Event>`. | | `event-stream` | `futures::Stream` producing `Result<Event>`. |
| `serde` | (De)serializing of events. | | `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 ### Dependency Justification
@ -151,9 +157,9 @@ features = ["event-stream"]
|:---------------|:---------------------------------------------------------------------------------|:--------------------------------------| |:---------------|:---------------------------------------------------------------------------------|:--------------------------------------|
| `bitflags` | `KeyModifiers`, those are differ based on input. | always | | `bitflags` | `KeyModifiers`, those are differ based on input. | always |
| `parking_lot` | locking `RwLock`s with a timeout, const mutexes. | 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 | | `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 | 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. | 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 | | `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 | | `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 | | `serde` | ***ser***ializing and ***de***serializing of events | only with `serde` feature flag |

View File

@ -48,10 +48,11 @@ use std::fmt;
use crate::Result; use crate::Result;
use crate::{csi, impl_display, Command}; use crate::{csi, impl_display, Command};
pub use sys::position;
pub(crate) mod sys; pub(crate) mod sys;
#[cfg(feature = "events")]
pub use sys::position;
/// A command that moves the terminal cursor to the given position (column, row). /// A command that moves the terminal cursor to the given position (column, row).
/// ///
/// # Notes /// # Notes
@ -426,13 +427,14 @@ impl_display!(for DisableBlinking);
impl_display!(for SetCursorStyle); impl_display!(for SetCursorStyle);
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "events")]
mod tests { mod tests {
use std::io::{self, stdout}; use std::io::{self, stdout};
use crate::execute; use crate::execute;
use super::{ 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 // Test is disabled, because it's failing on Travis

View File

@ -1,6 +1,7 @@
//! This module provides platform related functions. //! This module provides platform related functions.
#[cfg(unix)] #[cfg(unix)]
#[cfg(feature = "events")]
pub use self::unix::position; pub use self::unix::position;
#[cfg(windows)] #[cfg(windows)]
pub use self::windows::position; pub use self::windows::position;
@ -14,4 +15,5 @@ pub(crate) use self::windows::{
pub(crate) mod windows; pub(crate) mod windows;
#[cfg(unix)] #[cfg(unix)]
#[cfg(feature = "events")]
pub(crate) mod unix; pub(crate) mod unix;

View File

@ -80,37 +80,38 @@
//! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of //! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of
//! them (`event-*`). //! 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::fmt;
use std::hash::{Hash, Hasher};
#[cfg(windows)]
use std::io;
use std::time::Duration; use std::time::Duration;
use bitflags::bitflags;
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{csi, Command, Result}; use bitflags::bitflags;
use filter::{EventFilter, Filter}; use std::hash::{Hash, Hasher};
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;
/// Static instance of `InternalEventReader`. /// Static instance of `InternalEventReader`.
/// This needs to be static because there can be one event reader. /// This needs to be static because there can be one event reader.
static INTERNAL_EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None); 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| { MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
reader.get_or_insert_with(InternalEventReader::default) reader.get_or_insert_with(InternalEventReader::default)
}) })
@ -164,7 +165,7 @@ fn try_lock_internal_event_reader_for(
/// poll(Duration::from_millis(100)) /// 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) 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)? { match read_internal(&EventFilter)? {
InternalEvent::Event(event) => Ok(event), InternalEvent::Event(event) => Ok(event),
#[cfg(unix)] #[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. /// 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 where
F: Filter, F: Filter,
{ {
@ -234,7 +235,7 @@ where
} }
/// Reads a single `InternalEvent`. /// 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 where
F: Filter, F: Filter,
{ {
@ -242,12 +243,42 @@ where
reader.read(filter) 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. /// A command that enables mouse event capturing.
/// ///
/// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html). /// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
#[cfg(feature = "events")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EnableMouseCapture; pub struct EnableMouseCapture;
#[cfg(feature = "events")]
impl Command for EnableMouseCapture { impl Command for EnableMouseCapture {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(concat!( f.write_str(concat!(
@ -265,7 +296,7 @@ impl Command for EnableMouseCapture {
} }
#[cfg(windows)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { fn execute_winapi(&self) -> crate::Result<()> {
sys::windows::enable_mouse_capture() sys::windows::enable_mouse_capture()
} }
@ -294,7 +325,7 @@ impl Command for DisableMouseCapture {
} }
#[cfg(windows)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { fn execute_winapi(&self) -> crate::Result<()> {
sys::windows::disable_mouse_capture() sys::windows::disable_mouse_capture()
} }
@ -304,31 +335,81 @@ impl Command for DisableMouseCapture {
} }
} }
bitflags! { /// A command that enables focus event emission.
/// Represents special flags that tell compatible terminals to add extra information to keyboard events. ///
/// /// It should be paired with [`DisableFocusChange`] at the end of execution.
/// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information. ///
/// /// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
/// Alternate keys and Unicode codepoints are not yet supported by crossterm. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct EnableFocusChange;
pub struct KeyboardEnhancementFlags: u8 {
/// Represent Escape and modified keys using CSI-u sequences, so they can be unambiguously impl Command for EnableFocusChange {
/// read. fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001; f.write_str(csi!("?1004h"))
/// 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; #[cfg(windows)]
// Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes) fn execute_winapi(&self) -> crate::Result<()> {
// in addition to the base keycode. The alternate keycode overrides the base keycode in // Focus events are always enabled on Windows
// resulting `KeyEvent`s. Ok(())
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; /// A command that disables focus event emission.
// Send the Unicode codepoint as well as the keycode. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
// pub struct DisableFocusChange;
// *Note*: this is not yet supported by crossterm.
// const REPORT_ASSOCIATED_TEXT = 0b0001_0000; 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)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { fn execute_winapi(&self) -> crate::Result<()> {
use std::io;
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Unsupported, io::ErrorKind::Unsupported,
"Keyboard progressive enhancement not implemented for the legacy Windows API.", "Keyboard progressive enhancement not implemented for the legacy Windows API.",
@ -404,7 +487,9 @@ impl Command for PopKeyboardEnhancementFlags {
} }
#[cfg(windows)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { fn execute_winapi(&self) -> crate::Result<()> {
use std::io;
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Unsupported, io::ErrorKind::Unsupported,
"Keyboard progressive enhancement not implemented for the legacy Windows API.", "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. /// Represents an event.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))] #[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))]

View File

@ -1,12 +1,14 @@
use std::{collections::vec_deque::VecDeque, io, time::Duration}; use std::{collections::vec_deque::VecDeque, io, time::Duration};
#[cfg(unix)] #[cfg(unix)]
use super::source::unix::UnixInternalEventSource; use crate::event::source::unix::UnixInternalEventSource;
#[cfg(windows)] #[cfg(windows)]
use super::source::windows::WindowsEventSource; use crate::event::source::windows::WindowsEventSource;
#[cfg(feature = "event-stream")] #[cfg(feature = "event-stream")]
use super::sys::Waker; use crate::event::sys::Waker;
use super::{filter::Filter, source::EventSource, timeout::PollTimeout, InternalEvent, Result}; use crate::event::{filter::Filter, source::EventSource, timeout::PollTimeout, InternalEvent};
use crate::Result;
/// Can be used to read `InternalEvent`s. /// Can be used to read `InternalEvent`s.
pub(crate) struct InternalEventReader { pub(crate) struct InternalEventReader {
events: VecDeque<InternalEvent>, events: VecDeque<InternalEvent>,

View File

@ -8,14 +8,9 @@ use crate::Result;
#[cfg(feature = "event-stream")] #[cfg(feature = "event-stream")]
use crate::event::sys::Waker; use crate::event::sys::Waker;
use crate::event::{ use crate::event::{
source::EventSource, source::EventSource, sys::unix::parse::parse_event, timeout::PollTimeout, Event, InternalEvent,
sys::unix::{
file_descriptor::{tty_fd, FileDesc},
parse::parse_event,
},
timeout::PollTimeout,
Event, InternalEvent,
}; };
use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};
// Tokens to identify file descriptor // Tokens to identify file descriptor
const TTY_TOKEN: Token = Token(0); const TTY_TOKEN: Token = Token(0);

View File

@ -11,15 +11,8 @@ use filedescriptor::{poll, pollfd, POLLIN};
#[cfg(feature = "event-stream")] #[cfg(feature = "event-stream")]
use crate::event::sys::Waker; use crate::event::sys::Waker;
use crate::event::{source::EventSource, sys::unix::parse::parse_event, InternalEvent};
use crate::event::{ use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};
source::EventSource,
sys::unix::{
file_descriptor::{tty_fd, FileDesc},
parse::parse_event,
},
InternalEvent,
};
/// Holds a prototypical Waker and a receiver we can wait on when doing select(). /// Holds a prototypical Waker and a receiver we can wait on when doing select().
#[cfg(feature = "event-stream")] #[cfg(feature = "event-stream")]

View File

@ -8,12 +8,12 @@ use crate::event::{
}; };
#[cfg(feature = "event-stream")] #[cfg(feature = "event-stream")]
use super::super::sys::Waker; use crate::event::sys::Waker;
use super::super::{ use crate::event::{
source::EventSource, source::EventSource,
sys::windows::parse::{handle_key_event, handle_mouse_event}, sys::windows::parse::{handle_key_event, handle_mouse_event},
timeout::PollTimeout, timeout::PollTimeout,
InternalEvent, Result, InternalEvent,
}; };
pub(crate) struct WindowsEventSource { pub(crate) struct WindowsEventSource {
@ -24,7 +24,7 @@ pub(crate) struct WindowsEventSource {
} }
impl WindowsEventSource { impl WindowsEventSource {
pub(crate) fn new() -> Result<WindowsEventSource> { pub(crate) fn new() -> crate::Result<WindowsEventSource> {
let console = Console::from(Handle::current_in_handle()?); let console = Console::from(Handle::current_in_handle()?);
Ok(WindowsEventSource { Ok(WindowsEventSource {
console, console,
@ -41,7 +41,7 @@ impl WindowsEventSource {
} }
impl EventSource for 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); let poll_timeout = PollTimeout::new(timeout);
loop { loop {

View File

@ -14,7 +14,7 @@ use futures_core::stream::Stream;
use crate::Result; use crate::Result;
use super::{ use crate::event::{
filter::EventFilter, lock_internal_event_reader, poll_internal, read_internal, sys::Waker, filter::EventFilter, lock_internal_event_reader, poll_internal, read_internal, sys::Waker,
Event, InternalEvent, Event, InternalEvent,
}; };

View File

@ -1,5 +1,5 @@
#[cfg(feature = "event-stream")] #[cfg(feature = "event-stream")]
pub(crate) mod waker; pub(crate) mod waker;
pub(crate) mod file_descriptor; #[cfg(feature = "events")]
pub(crate) mod parse; pub(crate) mod parse;

View File

@ -1,6 +1,6 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use mio::{Registry, Token}; use ::mio::{Registry, Token};
use crate::Result; use crate::Result;
@ -8,7 +8,7 @@ use crate::Result;
/// This type wraps `mio::Waker`, for more information see its documentation. /// This type wraps `mio::Waker`, for more information see its documentation.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct Waker { pub(crate) struct Waker {
inner: Arc<Mutex<mio::Waker>>, inner: Arc<Mutex<::mio::Waker>>,
} }
impl Waker { impl Waker {

View File

@ -8,11 +8,10 @@ use crossterm_winapi::{ConsoleMode, Handle};
use crate::Result; use crate::Result;
#[cfg(feature = "event-stream")]
pub(crate) mod waker;
pub(crate) mod parse; pub(crate) mod parse;
pub(crate) mod poll; pub(crate) mod poll;
#[cfg(feature = "event-stream")]
pub(crate) mod waker;
const ENABLE_MOUSE_MODE: u32 = 0x0010 | 0x0080 | 0x0008; const ENABLE_MOUSE_MODE: u32 = 0x0010 | 0x0080 | 0x0008;

View File

@ -1,4 +1,4 @@
use crossterm_winapi::{ControlKeyState, EventFlags, KeyEventRecord, MouseEvent, ScreenBuffer}; use crossterm_winapi::{ControlKeyState, EventFlags, KeyEventRecord, ScreenBuffer};
use winapi::um::{ use winapi::um::{
wincon::{ wincon::{
CAPSLOCK_ON, LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED, CAPSLOCK_ON, LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED,
@ -13,7 +13,10 @@ use winapi::um::{
}; };
use crate::{ use crate::{
event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind}, event::{
Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEvent,
MouseEventKind,
},
Result, Result,
}; };
@ -25,7 +28,7 @@ pub struct MouseButtonsPressed {
} }
pub(crate) fn handle_mouse_event( pub(crate) fn handle_mouse_event(
mouse_event: MouseEvent, mouse_event: crossterm_winapi::MouseEvent,
buttons_pressed: &MouseButtonsPressed, buttons_pressed: &MouseButtonsPressed,
) -> Option<Event> { ) -> Option<Event> {
if let Ok(Some(event)) = parse_mouse_event_record(&mouse_event, buttons_pressed) { 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( fn parse_mouse_event_record(
event: &MouseEvent, event: &crossterm_winapi::MouseEvent,
buttons_pressed: &MouseButtonsPressed, buttons_pressed: &MouseButtonsPressed,
) -> Result<Option<crate::event::MouseEvent>> { ) -> Result<Option<MouseEvent>> {
let modifiers = KeyModifiers::from(&event.control_key_state); let modifiers = KeyModifiers::from(&event.control_key_state);
let xpos = event.mouse_position.x as u16; let xpos = event.mouse_position.x as u16;
@ -363,7 +366,7 @@ fn parse_mouse_event_record(
_ => None, _ => None,
}; };
Ok(kind.map(|kind| crate::event::MouseEvent { Ok(kind.map(|kind| MouseEvent {
kind, kind,
column: xpos, column: xpos,
row: ypos, row: ypos,

View File

@ -242,6 +242,7 @@ pub use crate::{
/// A module to work with the terminal cursor /// A module to work with the terminal cursor
pub mod cursor; pub mod cursor;
/// A module to read events. /// A module to read events.
#[cfg(feature = "events")]
pub mod event; pub mod event;
/// A module to apply attributes and colors on your text. /// A module to apply attributes and colors on your text.
pub mod style; pub mod style;

View File

@ -98,6 +98,7 @@ use crate::{csi, impl_display, Result};
pub(crate) mod sys; pub(crate) mod sys;
#[cfg(feature = "events")]
pub use sys::supports_keyboard_enhancement; pub use sys::supports_keyboard_enhancement;
/// Tells whether the raw mode is enabled. /// Tells whether the raw mode is enabled.

View File

@ -1,10 +1,12 @@
//! This module provides platform related functions. //! This module provides platform related functions.
#[cfg(unix)] #[cfg(unix)]
#[cfg(feature = "events")]
pub use self::unix::supports_keyboard_enhancement; pub use self::unix::supports_keyboard_enhancement;
#[cfg(unix)] #[cfg(unix)]
pub(crate) use self::unix::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled, size}; pub(crate) use self::unix::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled, size};
#[cfg(windows)] #[cfg(windows)]
#[cfg(feature = "events")]
pub use self::windows::supports_keyboard_enhancement; pub use self::windows::supports_keyboard_enhancement;
#[cfg(windows)] #[cfg(windows)]
pub(crate) use self::windows::{ pub(crate) use self::windows::{
@ -15,5 +17,7 @@ pub(crate) use self::windows::{
#[cfg(windows)] #[cfg(windows)]
mod windows; mod windows;
#[cfg(unix)]
pub mod file_descriptor;
#[cfg(unix)] #[cfg(unix)]
mod unix; mod unix;

View File

@ -1,21 +1,18 @@
//! UNIX related logic for terminal manipulation. //! UNIX related logic for terminal manipulation.
use std::fs::File; use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};
use std::io::Write;
use std::os::unix::io::{IntoRawFd, RawFd};
use std::time::Duration;
use std::{io, mem, process};
use libc::{ use libc::{
cfmakeraw, ioctl, tcgetattr, tcsetattr, termios as Termios, winsize, STDOUT_FILENO, TCSANOW, cfmakeraw, ioctl, tcgetattr, tcsetattr, termios as Termios, winsize, STDOUT_FILENO, TCSANOW,
TIOCGWINSZ, TIOCGWINSZ,
}; };
use parking_lot::Mutex; 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::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 // Some(Termios) -> we're in the raw mode and this is the previous mode
// None -> we're not in the raw 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 /// 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. /// [`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> { pub fn supports_keyboard_enhancement() -> Result<bool> {
if is_raw_mode_enabled() { if is_raw_mode_enabled() {
read_supports_keyboard_enhancement_raw() 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> { fn read_supports_keyboard_enhancement_flags() -> Result<bool> {
enable_raw_mode()?; enable_raw_mode()?;
let flags = read_supports_keyboard_enhancement_raw(); let flags = read_supports_keyboard_enhancement_raw();
@ -111,7 +110,15 @@ fn read_supports_keyboard_enhancement_flags() -> Result<bool> {
flags flags
} }
#[cfg(feature = "events")]
fn read_supports_keyboard_enhancement_raw() -> Result<bool> { 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. // 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 // 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 // query. If we receive the primary device attributes response but not the keyboard enhancement

View File

@ -61,6 +61,7 @@ pub(crate) fn size() -> Result<(u16, u16)> {
/// Queries the terminal's support for progressive keyboard enhancement. /// Queries the terminal's support for progressive keyboard enhancement.
/// ///
/// This always returns `Ok(false)` on Windows. /// This always returns `Ok(false)` on Windows.
#[cfg(feature = "events")]
pub fn supports_keyboard_enhancement() -> Result<bool> { pub fn supports_keyboard_enhancement() -> Result<bool> {
Ok(false) Ok(false)
} }