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
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

View File

@ -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"]

View File

@ -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 |

View File

@ -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

View File

@ -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;

View File

@ -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.
/// A command that enables focus event emission.
///
/// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information.
/// It should be paired with [`DisableFocusChange`] at the end of execution.
///
/// 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;
/// 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))]

View File

@ -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>,

View File

@ -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);

View File

@ -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")]

View File

@ -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 {

View File

@ -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,
};

View File

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

View File

@ -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 {

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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)
}