Skip to content

Commit

Permalink
restructure the whole event module
Browse files Browse the repository at this point in the history
  • Loading branch information
TimonPost committed Apr 7, 2023
1 parent a20bfca commit 764a577
Show file tree
Hide file tree
Showing 27 changed files with 193 additions and 185 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/crossterm_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ all-features = true
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"]
#
Expand Down
20 changes: 4 additions & 16 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,10 @@ use std::fmt;
use crate::{csi, Command};

#[cfg(feature = "events")]
pub(crate) mod filter;
mod event_api;
#[cfg(feature = "events")]
mod read;
#[cfg(feature = "events")]
mod source;
#[cfg(feature = "event-stream")]
#[cfg(feature = "events")]
mod stream;
#[cfg(feature = "events")]
mod timeout;

#[cfg(feature = "events")]
mod events_api;

#[cfg(feature = "events")]
pub use events_api::*;
pub use event_api::*;

pub(crate) mod sys;

/// A command that enables mouse event capturing.
///
Expand Down Expand Up @@ -140,9 +126,11 @@ impl Command for EnableMouseCapture {
/// A command that disables 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 DisableMouseCapture;

#[cfg(feature="events")]
impl Command for DisableMouseCapture {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
f.write_str(concat!(
Expand Down
19 changes: 19 additions & 0 deletions src/event/event_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
mod types;
mod api;
#[cfg(feature = "event-stream")]
pub(crate) mod waker;
pub(crate) mod filter;
pub(crate) mod read;
pub(crate) mod source;
#[cfg(feature = "event-stream")]
pub(crate) mod stream;
pub(crate) mod timeout;
pub(crate) mod sys;

#[cfg(feature = "event-stream")]
pub use stream::EventStream;

pub use self::{
types::*,
api::*
};
146 changes: 146 additions & 0 deletions src/event/event_api/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::{ time::Duration};
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
use crate::event::{
filter::{EventFilter, Filter},
read::InternalEventReader,
timeout::PollTimeout,
InternalEvent
};

use super::Event;

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

pub (super) fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
reader.get_or_insert_with(InternalEventReader::default)
})
}
fn try_lock_internal_event_reader_for(
duration: Duration,
) -> Option<MappedMutexGuard<'static, InternalEventReader>> {
Some(MutexGuard::map(
INTERNAL_EVENT_READER.try_lock_for(duration)?,
|reader| reader.get_or_insert_with(InternalEventReader::default),
))
}

/// Checks if there is an [`Event`](enum.Event.html) available.
///
/// Returns `Ok(true)` if an [`Event`](enum.Event.html) is available otherwise it returns `Ok(false)`.
///
/// `Ok(true)` guarantees that subsequent call to the [`read`](fn.read.html) function
/// won't block.
///
/// # Arguments
///
/// * `timeout` - maximum waiting time for event availability
///
/// # Examples
///
/// Return immediately:
///
/// ```no_run
/// use std::time::Duration;
///
/// use crossterm::{event::poll, Result};
///
/// fn is_event_available() -> Result<bool> {
/// // Zero duration says that the `poll` function must return immediately
/// // with an `Event` availability information
/// poll(Duration::from_secs(0))
/// }
/// ```
///
/// Wait up to 100ms:
///
/// ```no_run
/// use std::time::Duration;
///
/// use crossterm::{event::poll, Result};
///
/// fn is_event_available() -> Result<bool> {
/// // Wait for an `Event` availability for 100ms. It returns immediately
/// // if an `Event` is/becomes available.
/// poll(Duration::from_millis(100))
/// }
/// ```
pub fn poll(timeout: Duration) -> crate::Result<bool> {
poll_internal(Some(timeout), &EventFilter)
}

/// Reads a single [`Event`](enum.Event.html).
///
/// This function blocks until an [`Event`](enum.Event.html) is available. Combine it with the
/// [`poll`](fn.poll.html) function to get non-blocking reads.
///
/// # Examples
///
/// Blocking read:
///
/// ```no_run
/// use crossterm::{event::read, Result};
///
/// fn print_events() -> Result<bool> {
/// loop {
/// // Blocks until an `Event` is available
/// println!("{:?}", read()?);
/// }
/// }
/// ```
///
/// Non-blocking read:
///
/// ```no_run
/// use std::time::Duration;
///
/// use crossterm::{event::{read, poll}, Result};
///
/// fn print_events() -> Result<bool> {
/// loop {
/// if poll(Duration::from_millis(100))? {
/// // It's guaranteed that `read` won't block, because `poll` returned
/// // `Ok(true)`.
/// println!("{:?}", read()?);
/// } else {
/// // Timeout expired, no `Event` is available
/// }
/// }
/// }
/// ```
pub fn read() -> crate::Result<Event> {
match read_internal(&EventFilter)? {
InternalEvent::Event(event) => Ok(event),
#[cfg(unix)]
_ => unreachable!(),
}
}

/// 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) -> crate::Result<bool>
where
F: Filter,
{
let (mut reader, timeout) = if let Some(timeout) = timeout {
let poll_timeout = PollTimeout::new(Some(timeout));
if let Some(reader) = try_lock_internal_event_reader_for(timeout) {
(reader, poll_timeout.leftover())
} else {
return Ok(false);
}
} else {
(lock_internal_event_reader(), None)
};
reader.poll(timeout, filter)
}

/// Reads a single `InternalEvent`.
pub(crate) fn read_internal<F>(filter: &F) -> crate::Result<InternalEvent>
where
F: Filter,
{
let mut reader = lock_internal_event_reader();
reader.read(filter)
}
File renamed without changes.
9 changes: 5 additions & 4 deletions src/event/read.rs → src/event/event_api/read.rs
Original file line number Diff line number Diff line change
@@ -1,13 +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};
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>,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ 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,
Expand Down
4 changes: 2 additions & 2 deletions src/event/stream.rs → src/event/event_api/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use futures_core::stream::Stream;

use crate::Result;

use super::{
filter::EventFilter, lock_internal_event_reader, poll_internal, read_internal, sys::Waker,
use crate::event::{
filter::EventFilter, event_api::lock_internal_event_reader, poll_internal, read_internal, sys::Waker,
Event, InternalEvent,
};

Expand Down
File renamed without changes.
2 changes: 0 additions & 2 deletions src/event/sys/unix.rs → src/event/event_api/sys/unix.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#[cfg(feature = "event-stream")]
#[cfg(feature = "events")]
pub(crate) mod waker;

pub(crate) mod file_descriptor;
#[cfg(feature = "events")]
pub(crate) mod parse;
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ use crate::Result;

#[cfg(feature = "event-stream")]
pub(crate) mod waker;

#[cfg(feature = "events")]
pub(crate) mod parse;
#[cfg(feature = "events")]
pub(crate) mod poll;

const ENABLE_MOUSE_MODE: u32 = 0x0010 | 0x0080 | 0x0008;
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -13,7 +13,7 @@ use winapi::um::{
};

use crate::{
event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEventKind},
event::{Event, KeyCode, KeyEvent, KeyEventKind,MouseEvent, KeyModifiers, MouseButton, MouseEventKind},
Result,
};

Expand All @@ -25,7 +25,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) {
Expand Down Expand Up @@ -304,9 +304,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;
Expand Down Expand Up @@ -363,7 +363,7 @@ fn parse_mouse_event_record(
_ => None,
};

Ok(kind.map(|kind| crate::event::MouseEvent {
Ok(kind.map(|kind| MouseEvent {
kind,
column: xpos,
row: ypos,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 764a577

Please sign in to comment.