reis 0.3.0

Pure Rust implementation of libei/libeis protocol.
Documentation
use ashpd::desktop::input_capture::{Barrier, Capabilities, InputCapture};
use futures::stream::StreamExt;
use once_cell::sync::Lazy;
use reis::{
    ei,
    event::DeviceCapability,
    tokio::{EiConvertEventStream, EiEventStream},
};
use std::{collections::HashMap, os::unix::net::UnixStream};
use xkbcommon::xkb;

async fn open_connection() -> ei::Context {
    if let Some(context) = ei::Context::connect_to_env().unwrap() {
        context
    } else {
        eprintln!("Unable to find ei socket. Trying xdg desktop portal.");
        let input_capture = InputCapture::new().await.unwrap();
        let session = input_capture
            .create_session(
                &ashpd::WindowIdentifier::default(),
                (Capabilities::Keyboard | Capabilities::Pointer | Capabilities::Touchscreen).into(),
            )
            .await
            .unwrap()
            .0;
        let fd = input_capture.connect_to_eis(&session).await.unwrap();
        let stream = UnixStream::from(fd);
        let zones = input_capture
            .zones(&session)
            .await
            .unwrap()
            .response()
            .unwrap();

        let barriers = zones
            .regions()
            .iter()
            .enumerate()
            .map(|(n, region)| {
                let x = region.x_offset();
                let y = region.y_offset();
                let w = region.width() as i32;
                let h = region.height() as i32;
                Barrier::new(n as u32 + 1, (x, y, x + w - 1, y))
            })
            .collect::<Vec<_>>();
        let resp = input_capture
            .set_pointer_barriers(&session, &barriers, zones.zone_set())
            .await
            .unwrap()
            .response()
            .unwrap();
        assert_eq!(&resp.failed_barriers(), &[]);
        eprintln!("Set capture barrier to top edge of screen.");
        eprintln!("(When input is captured, Esc will exit.)");
        input_capture.enable(&session).await.unwrap();
        ei::Context::new(stream).unwrap()
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let context = open_connection().await;
    let mut events = EiEventStream::new(context.clone()).unwrap();
    let resp = reis::tokio::ei_handshake(
        &mut events,
        "receive-example",
        ei::handshake::ContextType::Receiver,
    )
    .await
    .unwrap();

    let mut events = EiConvertEventStream::new(events, resp);
    while let Some(event) = events.next().await {
        let event = event.unwrap();
        println!("{event:?}");
        match &event {
            reis::event::EiEvent::SeatAdded(evt) => {
                // println!("    capabilities: {:?}", evt.seat);
                evt.seat.bind_capabilities(&[
                    DeviceCapability::Pointer,
                    DeviceCapability::PointerAbsolute,
                    DeviceCapability::Keyboard,
                    DeviceCapability::Touch,
                    DeviceCapability::Scroll,
                    DeviceCapability::Button,
                ]);
                context.flush();
            }
            reis::event::EiEvent::DeviceAdded(evt) => {
                println!("  seat: {:?}", evt.device.seat().name());
                println!("  type: {:?}", evt.device.device_type());
                if let Some(dimensions) = evt.device.dimensions() {
                    println!("  dimensions: {:?}", dimensions);
                }
                println!("  regions: {:?}", evt.device.regions());
                if let Some(keymap) = evt.device.keymap() {
                    println!("  keymap: {:?}", keymap);
                }
                // Interfaces?
            }
            reis::event::EiEvent::KeyboardKey(evt) => {
                // Escape key
                if evt.key == 1 {
                    std::process::exit(0);
                }
            }
            _ => {}
        }
    }
}