summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorMaxwell Beck <max@rastertail.net>2025-06-28 20:11:42 -0500
committerMaxwell Beck <max@rastertail.net>2025-06-28 20:11:42 -0500
commitf563cd4905cf6909a80eb973df52ba2b4e63800b (patch)
treea5d549033ab6f690f240ceb20441b30203aedbbe /src/main.rs
parente15b681db958182ae112dc11f48330c0ece793a9 (diff)
Refactor
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs264
1 files changed, 157 insertions, 107 deletions
diff --git a/src/main.rs b/src/main.rs
index 81fa7a8..56586ee 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,13 +1,16 @@
-use std::{
-    env::{self},
-    pin::pin,
-    time::Duration,
-};
+use std::{collections::HashSet, pin::pin, time::Duration};
 
-use bluer::{Session, Uuid};
+use bluer::{
+    Adapter, AdapterEvent, Device, DiscoveryFilter, DiscoveryTransport, Session, Uuid,
+    gatt::{local::Profile, remote::Characteristic},
+};
+use evdev::{
+    AbsInfo, AbsoluteAxisCode, AttributeSet, EventType, InputEvent, KeyCode, MiscCode, PropType,
+    SynchronizationCode, UinputAbsSetup,
+    uinput::{VirtualDevice, VirtualDeviceBuilder},
+};
 use tokio::{select, time::interval};
 use tokio_stream::StreamExt;
-use uinput_tokio::event::{controller::Mouse, relative};
 
 const HID_SERVICE: Result<Uuid, uuid::Error> =
     Uuid::try_parse("00001812-0000-1000-8000-00805f9b34fb");
@@ -19,120 +22,167 @@ const MAGIC_REPORT: u8 = 240;
 const BUTTON_REPORT: u8 = 251;
 const TOUCH_REPORT: u8 = 252;
 
-#[tokio::main(flavor = "current_thread")]
-async fn main() -> bluer::Result<()> {
-    let mut udevice = uinput_tokio::default()
-        .unwrap()
-        .name("siriremote")
-        .unwrap()
-        .event(Mouse::Left)
-        .unwrap()
-        .event(relative::Position::X)
-        .unwrap()
-        .event(relative::Position::Y)
-        .unwrap()
-        .create()
-        .await
-        .unwrap();
+struct RemoteCharateristics {
+    touch: Characteristic,
+    button: Characteristic,
+}
 
-    let session = Session::new().await?;
-    let adapter = session.default_adapter().await?;
+impl RemoteCharateristics {
+    async fn get(device: &Device) -> bluer::Result<Self> {
+        let mut touch = None;
+        let mut button = None;
 
-    let addr = env::args()
-        .nth(1)
-        .expect("must pass address")
-        .parse()
-        .expect("invalid address");
-
-    eprintln!("connecting...");
-    let device = adapter.device(addr)?;
-    device.connect().await?;
-
-    let mut touch_char = None;
-    let mut button_char = None;
-    for service in device.services().await? {
-        if service.uuid().await? == HID_SERVICE.unwrap() {
-            for characteristic in service.characteristics().await? {
-                for descriptor in characteristic.descriptors().await? {
-                    if descriptor.uuid().await? == REPORT_REF.unwrap() {
-                        let resp = descriptor.read().await?;
-                        match resp[0] {
-                            MAGIC_REPORT => characteristic.write(&[0xf0, 0x00]).await?,
-                            TOUCH_REPORT => touch_char = Some(characteristic.clone()),
-                            BUTTON_REPORT => button_char = Some(characteristic.clone()),
-                            _ => {}
+        for service in device.services().await? {
+            if service.uuid().await? == HID_SERVICE.unwrap() {
+                for characteristic in service.characteristics().await? {
+                    for descriptor in characteristic.descriptors().await? {
+                        if descriptor.uuid().await? == REPORT_REF.unwrap() {
+                            let resp = descriptor.read().await?;
+                            match resp[0] {
+                                // MAGIC_REPORT => characteristic.write(&[0xf0, 0x00]).await?,
+                                TOUCH_REPORT => touch = Some(characteristic.clone()),
+                                BUTTON_REPORT => button = Some(characteristic.clone()),
+                                _ => {}
+                            }
                         }
                     }
                 }
             }
         }
+
+        Ok(Self {
+            touch: touch.expect("did not find touch characteristic"),
+            button: button.expect("did not find button characteristic"),
+        })
+    }
+}
+
+async fn find_remote(adapter: &Adapter, rssi_thresh: i16) -> bluer::Result<Device> {
+    let mut uuids = HashSet::new();
+    uuids.insert(HID_SERVICE.unwrap());
+
+    adapter
+        .set_discovery_filter(DiscoveryFilter {
+            transport: DiscoveryTransport::Le,
+            rssi: Some(rssi_thresh),
+            uuids,
+            ..Default::default()
+        })
+        .await?;
+    let mut discover = pin!(adapter.discover_devices().await?);
+    while let Some(evt) = discover.next().await {
+        if let AdapterEvent::DeviceAdded(mac) = evt {
+            let device = adapter.device(mac)?;
+            if let Some(data) = device.manufacturer_data().await? {
+                if data.contains_key(&0x4c) {
+                    return Ok(device);
+                }
+            }
+        }
+    }
+    panic!("discovery ended");
+}
+
+async fn run(adapter: &Adapter) -> bluer::Result<()> {
+    eprintln!("DBG searching");
+    let remote = find_remote(&adapter, -25).await?;
+
+    if !remote.is_paired().await? {
+        eprintln!("DBG pairing");
+        remote.pair().await?;
     }
 
-    eprintln!("connected");
-    let mut touch = pin!(touch_char.unwrap().notify().await?);
-    let mut button = pin!(button_char.unwrap().notify().await?);
-    let mut last = None;
-    let mut sdx = 0f32;
-    let mut sdy = 0f32;
+    eprintln!("DBG connecting");
+    remote.connect().await?;
+
+    let chars = RemoteCharateristics::get(&remote).await?;
+    let mut touch_stream = pin!(chars.touch.notify().await?);
+
+    eprintln!("DBG starting");
+    let mut keys = AttributeSet::new();
+    keys.insert(KeyCode::BTN_TOUCH);
+    keys.insert(KeyCode::BTN_TOOL_FINGER);
+
+    let mut msc = AttributeSet::new();
+    msc.insert(MiscCode::MSC_TIMESTAMP);
+
+    let mut props = AttributeSet::new();
+    props.insert(PropType::POINTER);
+
+    let mut uinput = VirtualDevice::builder()
+        .unwrap()
+        .name("Siri Remote")
+        .with_properties(&props)
+        .unwrap()
+        .with_keys(&keys)
+        .unwrap()
+        .with_absolute_axis(&UinputAbsSetup::new(
+            AbsoluteAxisCode::ABS_X,
+            AbsInfo::new(0, -2048, 2048, 32, 0, 16),
+        ))
+        .unwrap()
+        .with_absolute_axis(&UinputAbsSetup::new(
+            AbsoluteAxisCode::ABS_Y,
+            AbsInfo::new(0, -2048, 2048, 32, 0, 16),
+        ))
+        .unwrap()
+        .with_msc(&msc)
+        .unwrap()
+        .build()
+        .unwrap();
+
     let mut timer = interval(Duration::from_millis(1));
+    let mut x = 0f32;
+    let mut y = 0f32;
+    let mut tx = 0f32;
+    let mut ty = 0f32;
+    let mut touch = 0;
     loop {
         select! {
+            ev = touch_stream.next() => {
+                let ev = ev.unwrap();
+                tx = ((((ev[5] & 15) as u16) << 8) + ev[4] as u16) as f32;
+                ty = ((((ev[5] & !15) as u16) >> 4) + ((ev[6] as u16) << 4)) as f32;
+                if tx >= 2048.0 {
+                    tx -= 4096.0;
+                }
+                if ty >= 2048.0 {
+                    ty -= 4096.0;
+                }
+
+                touch = if ev[3] > 0 { 1 } else { 0 };
+                // ts = (((ev[2] as u16) << 8) + (ev[1] as u16)) as i32;
+            },
             _ = timer.tick() => {
-                udevice.send(relative::Position::X, sdx as i32).await.unwrap();
-                udevice.send(relative::Position::Y, sdy as i32).await.unwrap();
-                udevice.synchronize().await.unwrap();
+                x = 0.5 * x + 0.5 * tx;
+                y = 0.5 * y + 0.5 * ty;
 
-                sdx *= 0.97;
-                sdy *= 0.97;
+                uinput
+                    .emit(&[
+                        InputEvent::new(EventType::KEY.0, KeyCode::BTN_TOUCH.0, touch),
+                        InputEvent::new(EventType::KEY.0, KeyCode::BTN_TOOL_FINGER.0, touch),
+                        InputEvent::new(EventType::ABSOLUTE.0, AbsoluteAxisCode::ABS_X.0, x as i32),
+                        InputEvent::new(EventType::ABSOLUTE.0, AbsoluteAxisCode::ABS_Y.0, -y as i32),
+                        InputEvent::new(
+                            EventType::SYNCHRONIZATION.0,
+                            SynchronizationCode::SYN_REPORT.0,
+                            0,
+                        ),
+                    ])
+                    .unwrap();
             },
-            v = button.next() => {
-                let v = v.unwrap();
-                match (v[0], v[1]) {
-                    (8, 0) => {
-                        udevice.send(Mouse::Left, 1).await.unwrap();
-                    },
-                    (0, 0) => {
-                        udevice.send(Mouse::Left, 0).await.unwrap();
-                    },
-                    (_, _) => (),
-                }
-            }
-            v = touch.next() => {
-                let v = v.unwrap();
-                let ts = (((v[2] as u16) << 8) + (v[1] as u16)) as i32;
-                let touched = v[3] > 0;
-
-                let x = ((((v[5] & 15) as u16) << 8) + v[4] as u16) as i32;
-                let y = ((((v[5] & !15) as u16) >> 4) + ((v[6] as u16) << 4)) as i32;
-
-                if touched {
-                    if let Some(&(xp, yp, tsp)) = last.as_ref() {
-                        let mut dx: i32 = x - xp;
-                        let mut dy: i32 = y - yp;
-                        let mut dts: i32 = ts - tsp;
-                        if dx >= 2048 {
-                            dx -= 4096;
-                        }
-                        if dx <= -2048 {
-                            dx += 4096;
-                        }
-                        if dy >= -2048 {
-                            dy -= 4096;
-                        }
-                        if dy <= -2048 {
-                            dy += 4096;
-                        }
-                        if dts <= -32768 {
-                            dts += 65536;
-                        }
-                        sdx += (dx as f32) / (dts as f32);
-                        sdy -= (dy as f32) / (dts as f32);
-                    }
-                    last = Some((x, y, ts));
-                } else {
-                    last = None;
-                }
-            }
-        }
+        };
     }
 }
+
+#[tokio::main(flavor = "current_thread")]
+async fn main() -> bluer::Result<()> {
+    let session = Session::new().await?;
+    let adapter = session.default_adapter().await?;
+
+    if let Err(e) = run(&adapter).await {
+        eprintln!("ERR {e}");
+    }
+
+    Ok(())
+}