diff --git a/src/cursor/sys/unix.rs b/src/cursor/sys/unix.rs index 47342120..4b5617ef 100644 --- a/src/cursor/sys/unix.rs +++ b/src/cursor/sys/unix.rs @@ -4,7 +4,10 @@ use std::{ }; use crate::{ - event::{filter::CursorPositionFilter, poll_internal, read_internal, InternalEvent}, + event::{ + filter::CursorPositionFilter, + internal::{self, InternalEvent}, + }, terminal::{disable_raw_mode, enable_raw_mode, sys::is_raw_mode_enabled}, }; @@ -36,10 +39,10 @@ fn read_position_raw() -> io::Result<(u16, u16)> { stdout.flush()?; loop { - match poll_internal(Some(Duration::from_millis(2000)), &CursorPositionFilter) { + match internal::poll(Some(Duration::from_millis(2000)), &CursorPositionFilter) { Ok(true) => { if let Ok(InternalEvent::CursorPosition(x, y)) = - read_internal(&CursorPositionFilter) + internal::read(&CursorPositionFilter) { return Ok((x, y)); } diff --git a/src/event.rs b/src/event.rs index 457c4162..cc6c46d2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -119,6 +119,7 @@ //! them (`event-*`). pub(crate) mod filter; +pub(crate) mod internal; pub(crate) mod read; pub(crate) mod source; #[cfg(feature = "event-stream")] @@ -131,37 +132,13 @@ use derive_more::derive::IsVariant; #[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 crate::{csi, event::filter::EventFilter, Command}; use std::fmt::{self, Display}; use std::time::Duration; 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> = parking_lot::const_mutex(None); - -pub(crate) 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> { - 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)`. @@ -202,7 +179,7 @@ fn try_lock_internal_event_reader_for( /// } /// ``` pub fn poll(timeout: Duration) -> std::io::Result { - poll_internal(Some(timeout), &EventFilter) + internal::poll(Some(timeout), &EventFilter) } /// Reads a single [`Event`](enum.Event.html). @@ -247,40 +224,13 @@ pub fn poll(timeout: Duration) -> std::io::Result { /// } /// ``` pub fn read() -> std::io::Result { - match read_internal(&EventFilter)? { - InternalEvent::Event(event) => Ok(event), + match internal::read(&EventFilter)? { + internal::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(timeout: Option, filter: &F) -> std::io::Result -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(filter: &F) -> std::io::Result -where - F: Filter, -{ - let mut reader = lock_internal_event_reader(); - reader.read(filter) -} - bitflags! { /// Represents special flags that tell compatible terminals to add extra information to keyboard events. /// @@ -1467,25 +1417,6 @@ impl Display for KeyCode { } } -/// An internal event. -/// -/// Encapsulates publicly available `Event` with additional internal -/// events that shouldn't be publicly available to the crate users. -#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)] -pub(crate) enum InternalEvent { - /// An event. - Event(Event), - /// A cursor position (`col`, `row`). - #[cfg(unix)] - CursorPosition(u16, u16), - /// The progressive keyboard enhancement flags enabled by the terminal. - #[cfg(unix)] - KeyboardEnhancementFlags(KeyboardEnhancementFlags), - /// Attributes and architectural class of the terminal. - #[cfg(unix)] - PrimaryDeviceAttributes, -} - #[cfg(test)] mod tests { use std::collections::hash_map::DefaultHasher; diff --git a/src/event/filter.rs b/src/event/filter.rs index cd7abce2..b939a297 100644 --- a/src/event/filter.rs +++ b/src/event/filter.rs @@ -1,4 +1,4 @@ -use crate::event::InternalEvent; +use crate::event::internal::InternalEvent; /// Interface for filtering an `InternalEvent`. pub(crate) trait Filter: Send + Sync + 'static { diff --git a/src/event/internal.rs b/src/event/internal.rs new file mode 100644 index 00000000..b63bdbd3 --- /dev/null +++ b/src/event/internal.rs @@ -0,0 +1,72 @@ +use std::time::Duration; + +use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; + +#[cfg(unix)] +use crate::event::KeyboardEnhancementFlags; +use crate::event::{filter::Filter, read::InternalEventReader, timeout::PollTimeout, Event}; + +/// Static instance of `InternalEventReader`. +/// This needs to be static because there can be one event reader. +static EVENT_READER: Mutex> = parking_lot::const_mutex(None); + +pub(crate) fn lock_event_reader() -> MappedMutexGuard<'static, InternalEventReader> { + MutexGuard::map(EVENT_READER.lock(), |reader| { + reader.get_or_insert_with(InternalEventReader::default) + }) +} + +fn try_lock_event_reader_for( + duration: Duration, +) -> Option> { + Some(MutexGuard::map( + EVENT_READER.try_lock_for(duration)?, + |reader| reader.get_or_insert_with(InternalEventReader::default), + )) +} + +/// Polls to check if there are any `InternalEvent`s that can be read within the given duration. +pub(crate) fn poll(timeout: Option, filter: &F) -> std::io::Result +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_event_reader_for(timeout) { + (reader, poll_timeout.leftover()) + } else { + return Ok(false); + } + } else { + (lock_event_reader(), None) + }; + reader.poll(timeout, filter) +} + +/// Reads a single `InternalEvent`. +pub(crate) fn read(filter: &F) -> std::io::Result +where + F: Filter, +{ + let mut reader = lock_event_reader(); + reader.read(filter) +} + +/// An internal event. +/// +/// Encapsulates publicly available `Event` with additional internal +/// events that shouldn't be publicly available to the crate users. +#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)] +pub(crate) enum InternalEvent { + /// An event. + Event(Event), + /// A cursor position (`col`, `row`). + #[cfg(unix)] + CursorPosition(u16, u16), + /// The progressive keyboard enhancement flags enabled by the terminal. + #[cfg(unix)] + KeyboardEnhancementFlags(KeyboardEnhancementFlags), + /// Attributes and architectural class of the terminal. + #[cfg(unix)] + PrimaryDeviceAttributes, +} diff --git a/src/event/read.rs b/src/event/read.rs index 22f989b4..8f2c02a7 100644 --- a/src/event/read.rs +++ b/src/event/read.rs @@ -6,7 +6,9 @@ use crate::event::source::unix::UnixInternalEventSource; use crate::event::source::windows::WindowsEventSource; #[cfg(feature = "event-stream")] use crate::event::sys::Waker; -use crate::event::{filter::Filter, source::EventSource, timeout::PollTimeout, InternalEvent}; +use crate::event::{ + filter::Filter, internal::InternalEvent, source::EventSource, timeout::PollTimeout, +}; /// Can be used to read `InternalEvent`s. pub(crate) struct InternalEventReader { diff --git a/src/event/source.rs b/src/event/source.rs index e53bd31e..12b84d90 100644 --- a/src/event/source.rs +++ b/src/event/source.rs @@ -1,8 +1,8 @@ use std::{io, time::Duration}; +use super::internal::InternalEvent; #[cfg(feature = "event-stream")] use super::sys::Waker; -use super::InternalEvent; #[cfg(unix)] pub(crate) mod unix; diff --git a/src/event/source/unix/mio.rs b/src/event/source/unix/mio.rs index 6d19e0c5..e5f8e2e7 100644 --- a/src/event/source/unix/mio.rs +++ b/src/event/source/unix/mio.rs @@ -6,7 +6,8 @@ use signal_hook_mio::v1_0::Signals; #[cfg(feature = "event-stream")] use crate::event::sys::Waker; use crate::event::{ - source::EventSource, sys::unix::parse::parse_event, timeout::PollTimeout, Event, InternalEvent, + internal::InternalEvent, source::EventSource, sys::unix::parse::parse_event, + timeout::PollTimeout, Event, }; use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc}; diff --git a/src/event/source/unix/tty.rs b/src/event/source/unix/tty.rs index 1da32f6f..abc91ff8 100644 --- a/src/event/source/unix/tty.rs +++ b/src/event/source/unix/tty.rs @@ -13,7 +13,7 @@ use filedescriptor::{poll, pollfd, POLLIN}; #[cfg(feature = "event-stream")] use crate::event::sys::Waker; -use crate::event::{source::EventSource, sys::unix::parse::parse_event, InternalEvent}; +use crate::event::{internal::InternalEvent, source::EventSource, sys::unix::parse::parse_event}; use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc}; /// Holds a prototypical Waker and a receiver we can wait on when doing select(). diff --git a/src/event/source/windows.rs b/src/event/source/windows.rs index fa40cc50..9d60cc2f 100644 --- a/src/event/source/windows.rs +++ b/src/event/source/windows.rs @@ -10,10 +10,10 @@ use crate::event::{ #[cfg(feature = "event-stream")] use crate::event::sys::Waker; use crate::event::{ + internal::InternalEvent, source::EventSource, sys::windows::parse::{handle_key_event, handle_mouse_event}, timeout::PollTimeout, - InternalEvent, }; pub(crate) struct WindowsEventSource { diff --git a/src/event/stream.rs b/src/event/stream.rs index e74dceae..5f27a331 100644 --- a/src/event/stream.rs +++ b/src/event/stream.rs @@ -14,8 +14,10 @@ use std::{ use futures_core::stream::Stream; use crate::event::{ - filter::EventFilter, lock_internal_event_reader, poll_internal, read_internal, sys::Waker, - Event, InternalEvent, + filter::EventFilter, + internal::{self, InternalEvent}, + sys::Waker, + Event, }; /// A stream of `Result`. @@ -44,7 +46,7 @@ impl Default for EventStream { thread::spawn(move || { while let Ok(task) = receiver.recv() { loop { - if let Ok(true) = poll_internal(None, &EventFilter) { + if let Ok(true) = internal::poll(None, &EventFilter) { break; } @@ -59,7 +61,7 @@ impl Default for EventStream { }); EventStream { - poll_internal_waker: lock_internal_event_reader().waker(), + poll_internal_waker: internal::lock_event_reader().waker(), stream_wake_task_executed: Arc::new(AtomicBool::new(false)), stream_wake_task_should_shutdown: Arc::new(AtomicBool::new(false)), task_sender, @@ -102,8 +104,8 @@ impl Stream for EventStream { type Item = io::Result; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let result = match poll_internal(Some(Duration::from_secs(0)), &EventFilter) { - Ok(true) => match read_internal(&EventFilter) { + let result = match internal::poll(Some(Duration::from_secs(0)), &EventFilter) { + Ok(true) => match internal::read(&EventFilter) { Ok(InternalEvent::Event(event)) => Poll::Ready(Some(Ok(event))), Err(e) => Poll::Ready(Some(Err(e))), #[cfg(unix)] diff --git a/src/event/sys/unix/parse.rs b/src/event/sys/unix/parse.rs index 29377438..8897096c 100644 --- a/src/event/sys/unix/parse.rs +++ b/src/event/sys/unix/parse.rs @@ -5,7 +5,7 @@ use crate::event::{ MediaKeyCode, ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind, }; -use super::super::super::InternalEvent; +use crate::event::internal::InternalEvent; // Event parsing // diff --git a/src/terminal/sys/unix.rs b/src/terminal/sys/unix.rs index f4ada156..a9e9ec04 100644 --- a/src/terminal/sys/unix.rs +++ b/src/terminal/sys/unix.rs @@ -214,7 +214,7 @@ fn query_keyboard_enhancement_flags_nonraw() -> io::Result io::Result> { use crate::event::{ filter::{KeyboardEnhancementFlagsFilter, PrimaryDeviceAttributesFilter}, - poll_internal, read_internal, InternalEvent, + internal::{self, InternalEvent}, }; use std::io::Write; use std::time::Duration; @@ -241,15 +241,15 @@ fn query_keyboard_enhancement_flags_raw() -> io::Result { - match read_internal(&KeyboardEnhancementFlagsFilter) { + match internal::read(&KeyboardEnhancementFlagsFilter) { Ok(InternalEvent::KeyboardEnhancementFlags(current_flags)) => { // Flush the PrimaryDeviceAttributes out of the event queue. - read_internal(&PrimaryDeviceAttributesFilter).ok(); + internal::read(&PrimaryDeviceAttributesFilter).ok(); return Ok(Some(current_flags)); } _ => return Ok(None),