mod global;
pub mod message_loop;
mod types;
pub mod window;
use core::{
error::Error,
fmt::Display,
sync::atomic::{AtomicBool, Ordering},
};
use anyhow::Context;
use asdf_overlay_window_event::Event;
use once_cell::sync::OnceCell;
use windows::Win32::UI::WindowsAndMessaging::HCURSOR;
use crate::{global::GlobalState, message_loop::MessageLoopState, window::WindowProcState};
static GLOBAL: OnceCell<GlobalState> = OnceCell::new();
pub struct Backends {
event_rx: flume::Receiver<Event>,
}
impl Backends {
pub fn new() -> anyhow::Result<Self> {
let (event_tx, event_rx) = flume::unbounded();
let init_inner = || -> anyhow::Result<GlobalState> {
global::hook::install()?;
message_loop::hook::install()?;
Ok(GlobalState::new(event_tx))
};
static INITIALIZED: AtomicBool = AtomicBool::new(false);
if INITIALIZED.swap(true, Ordering::SeqCst) {
panic!("GlobalInputManager can only be initialized once");
}
GLOBAL
.get_or_try_init(init_inner)
.context("initialization failed")?;
Ok(Self { event_rx })
}
pub fn recv(&self) -> Option<Event> {
self.event_rx.recv().ok()
}
pub async fn recv_async(&self) -> Option<Event> {
self.event_rx.recv_async().await.ok()
}
pub fn try_recv(&self) -> Result<Event, TryRecvError> {
Ok(self.event_rx.try_recv()?)
}
pub fn windows(&self) -> impl Iterator<Item = u32> + '_ {
Self::get().windows.iter().map(|r| *r.key())
}
pub fn window<R>(&self, id: u32, f: impl FnOnce(&WindowProcState) -> R) -> Option<R> {
Self::get().windows.view(&id, |_, state| f(state))
}
pub fn message_loops(&self) -> impl Iterator<Item = u32> + '_ {
Self::get().message_loops.iter().map(|r| *r.key())
}
pub fn message_loop<R>(&self, id: u32, f: impl FnOnce(&MessageLoopState) -> R) -> Option<R> {
Self::get().message_loops.view(&id, |_, state| f(state))
}
#[inline]
pub fn input_blocked() -> bool {
Self::get().input_blocked()
}
#[inline]
pub fn block_input(&self) {
Self::get().block_input();
}
#[inline]
pub fn unblock_input(&self) {
Self::get().unblock_input();
}
#[inline]
pub fn set_blocking_cursor(&self, cursor: Option<HCURSOR>) {
Self::get().set_blocking_cursor(cursor);
}
pub fn reset(&self) {
Self::get().reset();
}
#[inline]
fn get() -> &'static GlobalState {
GLOBAL.get().expect("Backends is not initialized")
}
}
impl Drop for Backends {
fn drop(&mut self) {
Self::get().unblock_input();
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TryRecvError {
Empty,
Disconnected,
}
impl From<flume::TryRecvError> for TryRecvError {
fn from(err: flume::TryRecvError) -> Self {
match err {
flume::TryRecvError::Empty => TryRecvError::Empty,
flume::TryRecvError::Disconnected => TryRecvError::Disconnected,
}
}
}
impl Display for TryRecvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TryRecvError::Empty => flume::TryRecvError::Empty.fmt(f),
TryRecvError::Disconnected => flume::TryRecvError::Disconnected.fmt(f),
}
}
}
impl Error for TryRecvError {}