diff options
author | Maxwell Beck <max@rastertail.net> | 2025-06-28 20:11:42 -0500 |
---|---|---|
committer | Maxwell Beck <max@rastertail.net> | 2025-06-28 20:11:42 -0500 |
commit | f563cd4905cf6909a80eb973df52ba2b4e63800b (patch) | |
tree | a5d549033ab6f690f240ceb20441b30203aedbbe /src/main.rs | |
parent | e15b681db958182ae112dc11f48330c0ece793a9 (diff) |
Refactor
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 264 |
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(()) +} |