use crate::input::keyboard::key::KeyboardKey;
use ampsc::{ChannelConsumer, ChannelProducer};
use atspi::events::mouse::ButtonEvent;
use atspi::proxy::device_event_controller::{DeviceEvent, DeviceEventControllerProxy, EventType};
use some_executor::hint::Hint;
use some_executor::task::{Configuration, Task};
use some_executor::{Priority, SomeExecutor};
use std::sync::OnceLock;
use std::time::Instant;
mod helpers;
mod keycode;
mod keyname;
mod keysym;
use helpers::{key_is_text_input, key_to_modifier};
use keycode::key_to_x11;
use keyname::key_to_name;
use keysym::key_to_id;
static ONCE_SENDER: OnceLock<ChannelProducer<Event>> = OnceLock::new();
enum Event {
Key(KeyboardKey, bool),
Mouse(),
}
async fn ax_loop(mut receiver: ChannelConsumer<Event>) {
let connection = atspi::AccessibilityConnection::new().await;
let connection = match connection {
Ok(c) => c,
Err(e) => {
logwise::error_async!(
"Failed to connect to ATSPI: {e}",
e = logwise::privacy::LogIt(e)
);
return;
}
};
let start_time = Instant::now();
let device = DeviceEventControllerProxy::new(connection.connection())
.await
.expect("No device event controller proxy");
let mut modifiers: i32 = 0;
loop {
let event = receiver.receive().await.expect("No event");
match event {
Event::Key(key, pressed) => {
let event_type = if pressed {
EventType::KeyPressed
} else {
EventType::KeyReleased
};
let is_lock = key == KeyboardKey::CapsLock || key == KeyboardKey::NumLock;
let late_toggle_off;
if is_lock {
if !pressed {
if key_to_modifier(key) & modifiers == 0 {
modifiers |= key_to_modifier(key);
late_toggle_off = false;
} else {
late_toggle_off = true;
}
} else {
late_toggle_off = false;
}
} else {
late_toggle_off = false;
}
let is_numlock_enabled = modifiers & key_to_modifier(KeyboardKey::NumLock) != 0;
let device_event = DeviceEvent {
event_type,
id: key_to_id(key, is_numlock_enabled),
hw_code: key_to_x11(key),
modifiers,
timestamp: start_time.elapsed().as_millis() as i32,
event_string: key_to_name(key, is_numlock_enabled),
is_text: key_is_text_input(key),
};
device
.notify_listeners_sync(&device_event)
.await
.expect("Failed to notify listeners");
if is_lock {
if late_toggle_off {
modifiers &= !key_to_modifier(key);
}
} else {
if pressed {
modifiers |= key_to_modifier(key);
} else {
modifiers &= !key_to_modifier(key);
}
}
}
Event::Mouse() => {
let event = ButtonEvent {
item: Default::default(),
detail: "".to_string(),
mouse_x: 0,
mouse_y: 0,
};
connection
.send_event(event)
.await
.expect("Can't send event");
}
}
}
}
fn ax_init() -> ChannelProducer<Event> {
ONCE_SENDER
.get_or_init(|| {
let (sender, receiver) = ampsc::channel();
let mut ex = some_executor::current_executor::current_executor();
let t = Task::without_notifications(
"linux ax".to_string(),
Configuration::new(Hint::IO, Priority::UserInteractive, Instant::now()),
ax_loop(receiver),
)
.into_objsafe();
let o = ex.spawn_objsafe(t);
std::mem::forget(o);
sender
})
.clone()
}
pub fn ax_press(key: KeyboardKey, pressed: bool) {
let sender = ax_init();
let mut ex = some_executor::current_executor::current_executor();
let t = Task::without_notifications(
"linux ax".to_string(),
Configuration::new(Hint::IO, Priority::UserInteractive, Instant::now()),
async move {
let mut sender = sender;
sender
.send(Event::Key(key, pressed))
.await
.expect("Failed to send event");
sender.async_drop().await;
},
)
.into_objsafe();
let o = ex.spawn_objsafe(t);
std::mem::forget(o);
}
pub fn ax_mouse() {
let sender = ax_init();
let mut ex = some_executor::current_executor::current_executor();
let t = Task::without_notifications(
"linux ax".to_string(),
Configuration::new(Hint::IO, Priority::UserInteractive, Instant::now()),
async move {
let mut sender = sender;
sender
.send(Event::Mouse())
.await
.expect("Failed to send event");
sender.async_drop().await;
},
)
.into_objsafe();
let o = ex.spawn_objsafe(t);
std::mem::forget(o);
}