update for client to server communications
This commit is contained in:
parent
b8183d6861
commit
93991ee9db
@ -98,8 +98,8 @@ impl NavkaClientApp {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// fresh channel for aggregator => we do this with new (tx, rx)
|
// fresh channel for aggregator => we do this with new (tx, rx)
|
||||||
let (_tx, rx) = mpsc::channel::<HidReport>(32);
|
let (tx, rx) = mpsc::channel::<HidReport>(64);
|
||||||
// aggregator can hold 'tx' by storing in some global or so?
|
let mut aggregator = InputAggregator::new(dev_mode, tx.clone());
|
||||||
|
|
||||||
let outbound = ReceiverStream::new(rx);
|
let outbound = ReceiverStream::new(rx);
|
||||||
let response = match client.stream(Request::new(outbound)).await {
|
let response = match client.stream(Request::new(outbound)).await {
|
||||||
|
|||||||
@ -3,8 +3,11 @@
|
|||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use evdev::{Device, EventType, KeyCode, RelativeAxisCode};
|
use evdev::{Device, EventType, KeyCode, RelativeAxisCode};
|
||||||
use tokio::time::{interval, Duration};
|
use tokio::time::{interval, Duration};
|
||||||
|
use tokio::sync::mpsc::{self, Sender};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
|
use navka_common::navka::HidReport;
|
||||||
|
|
||||||
use crate::input::keyboard::KeyboardAggregator;
|
use crate::input::keyboard::KeyboardAggregator;
|
||||||
use crate::input::mouse::MouseAggregator;
|
use crate::input::mouse::MouseAggregator;
|
||||||
use crate::input::camera::CameraCapture;
|
use crate::input::camera::CameraCapture;
|
||||||
@ -15,6 +18,7 @@ use crate::input::microphone::MicrophoneCapture;
|
|||||||
/// spawns specialized aggregator objects, and can also
|
/// spawns specialized aggregator objects, and can also
|
||||||
/// create stubs for camera/microphone logic if needed.
|
/// create stubs for camera/microphone logic if needed.
|
||||||
pub struct InputAggregator {
|
pub struct InputAggregator {
|
||||||
|
tx: Sender<HidReport>,
|
||||||
pub dev_mode: bool,
|
pub dev_mode: bool,
|
||||||
keyboards: Vec<KeyboardAggregator>,
|
keyboards: Vec<KeyboardAggregator>,
|
||||||
mice: Vec<MouseAggregator>,
|
mice: Vec<MouseAggregator>,
|
||||||
@ -68,7 +72,8 @@ impl InputAggregator {
|
|||||||
info!("Grabbed keyboard {:?}", dev.name().unwrap_or("UNKNOWN"));
|
info!("Grabbed keyboard {:?}", dev.name().unwrap_or("UNKNOWN"));
|
||||||
|
|
||||||
// pass dev_mode to aggregator
|
// pass dev_mode to aggregator
|
||||||
let kbd_agg = KeyboardAggregator::new(dev, self.dev_mode);
|
// let kbd_agg = KeyboardAggregator::new(dev, self.dev_mode);
|
||||||
|
let kbd_agg = KeyboardAggregator::new(dev.clone(), self.dev_mode, self.tx.clone());
|
||||||
self.keyboards.push(kbd_agg);
|
self.keyboards.push(kbd_agg);
|
||||||
found_any = true;
|
found_any = true;
|
||||||
continue;
|
continue;
|
||||||
@ -77,7 +82,8 @@ impl InputAggregator {
|
|||||||
dev.grab().with_context(|| format!("grabbing mouse {path:?}"))?;
|
dev.grab().with_context(|| format!("grabbing mouse {path:?}"))?;
|
||||||
info!("Grabbed mouse {:?}", dev.name().unwrap_or("UNKNOWN"));
|
info!("Grabbed mouse {:?}", dev.name().unwrap_or("UNKNOWN"));
|
||||||
|
|
||||||
let mouse_agg = MouseAggregator::new(dev);
|
// let mouse_agg = MouseAggregator::new(dev);np
|
||||||
|
let mouse_agg = MouseAggregator::new(dev.clone(), self.tx.clone());
|
||||||
self.mice.push(mouse_agg);
|
self.mice.push(mouse_agg);
|
||||||
found_any = true;
|
found_any = true;
|
||||||
continue;
|
continue;
|
||||||
@ -118,6 +124,10 @@ impl InputAggregator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(dev_mode: bool, tx: Sender<HidReport>) -> Self {
|
||||||
|
Self { tx, dev_mode, keyboards: Vec::new(), mice: Vec::new(), camera: None, mic: None }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Classification {
|
struct Classification {
|
||||||
keyboard: Option<()>,
|
keyboard: Option<()>,
|
||||||
|
|||||||
@ -9,15 +9,17 @@ use crate::input::keymap::{keycode_to_usage, is_modifier};
|
|||||||
/// The aggregator logic for a single keyboard device.
|
/// The aggregator logic for a single keyboard device.
|
||||||
pub struct KeyboardAggregator {
|
pub struct KeyboardAggregator {
|
||||||
dev: Device,
|
dev: Device,
|
||||||
|
tx: Sender<HidReport>,
|
||||||
dev_mode: bool,
|
dev_mode: bool,
|
||||||
pressed_keys: HashSet<KeyCode>,
|
pressed_keys: HashSet<KeyCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardAggregator {
|
impl KeyboardAggregator {
|
||||||
pub fn new(mut dev: Device, dev_mode: bool) -> Self {
|
pub fn new(dev: Device, dev_mode: bool, tx: Sender<HidReport>) -> Self {
|
||||||
let _ = dev.set_nonblocking(true);
|
let _ = dev.set_nonblocking(true);
|
||||||
Self {
|
Self {
|
||||||
dev,
|
dev,
|
||||||
|
tx: Sender<HidReport>,
|
||||||
dev_mode,
|
dev_mode,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
}
|
}
|
||||||
@ -102,6 +104,10 @@ impl KeyboardAggregator {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = self.tx.try_send(HidReport {
|
||||||
|
kind: Some(navka_common::navka::hid_report::Kind::KeyboardReport(report.to_vec())),
|
||||||
|
});
|
||||||
|
|
||||||
fn is_magic_chord(&self) -> bool {
|
fn is_magic_chord(&self) -> bool {
|
||||||
self.pressed_keys.contains(&KeyCode::KEY_LEFTCTRL)
|
self.pressed_keys.contains(&KeyCode::KEY_LEFTCTRL)
|
||||||
&& self.pressed_keys.contains(&KeyCode::KEY_ESC)
|
&& self.pressed_keys.contains(&KeyCode::KEY_ESC)
|
||||||
|
|||||||
@ -6,9 +6,11 @@ use tracing::error;
|
|||||||
/// Aggregator for a single mouse device
|
/// Aggregator for a single mouse device
|
||||||
pub struct MouseAggregator {
|
pub struct MouseAggregator {
|
||||||
dev: Device,
|
dev: Device,
|
||||||
dx: i32,
|
tx: Sender<HidReport>,
|
||||||
dy: i32,
|
buttons: u8,
|
||||||
// etc
|
dx: i8,
|
||||||
|
dy: i8,
|
||||||
|
wheel: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseAggregator {
|
impl MouseAggregator {
|
||||||
@ -38,18 +40,27 @@ impl MouseAggregator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_event(&mut self, ev: InputEvent) {
|
fn handle_event(&mut self, ev: InputEvent) {
|
||||||
if ev.event_type() == EventType::RELATIVE {
|
match ev.event_type() {
|
||||||
match RelativeAxisCode(ev.code()) {
|
EventType::RELATIVE => { /* fill dx/dy/wheel as i8 */ }
|
||||||
RelativeAxisCode::REL_X => {
|
EventType::KEY => { // buttons are REPORTED as KEYS (BTN_LEFT…)
|
||||||
self.dx += ev.value();
|
let pressed = ev.value() != 0;
|
||||||
|
match ev.code() {
|
||||||
|
c if c == KeyCode::BTN_LEFT.0 => self.set_btn(0, pressed),
|
||||||
|
c if c == KeyCode::BTN_RIGHT.0 => self.set_btn(1, pressed),
|
||||||
|
c if c == KeyCode::BTN_MIDDLE.0=> self.set_btn(2, pressed),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
RelativeAxisCode::REL_Y => {
|
|
||||||
self.dy += ev.value();
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
tracing::debug!("mouse dx={} dy={}", self.dx, self.dy);
|
|
||||||
}
|
// whenever we changed something, emit:
|
||||||
// etc. Also handle buttons with KEY_B?
|
let rep = [self.buttons, self.dx as u8, self.dy as u8, self.wheel as u8];
|
||||||
|
let _ = self.tx.try_send(HidReport {
|
||||||
|
kind: Some(navka_common::navka::hid_report::Kind::MouseReport(rep.to_vec())),
|
||||||
|
});
|
||||||
|
// reset deltas so we send *relative* movement
|
||||||
|
self.dx = 0; self.dy = 0; self.wheel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
package navka;
|
package navka;
|
||||||
|
|
||||||
message HidReport { bytes data = 1; }
|
message HidReport {
|
||||||
|
oneof kind {
|
||||||
|
bytes keyboard_report = 1; // exactly 8 bytes
|
||||||
|
bytes mouse_report = 2; // exactly 4 bytes (btn, dx, dy, wheel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
service Relay {
|
service Relay {
|
||||||
rpc Stream (stream HidReport) returns (stream HidReport);
|
rpc Stream (stream HidReport) returns (stream HidReport);
|
||||||
|
|||||||
@ -45,6 +45,14 @@ echo 8 >"$G/functions/hid.usb0/report_length"
|
|||||||
printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x01\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x01\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' \
|
printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x01\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x01\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' \
|
||||||
> "$G/functions/hid.usb0/report_desc"
|
> "$G/functions/hid.usb0/report_desc"
|
||||||
|
|
||||||
|
# usb1 = mouse
|
||||||
|
mkdir -p "$G/functions/hid.usb1"
|
||||||
|
echo 2 > "$G/functions/hid.usb1/protocol"
|
||||||
|
echo 1 > "$G/functions/hid.usb1/subclass"
|
||||||
|
echo 4 > "$G/functions/hid.usb1/report_length"
|
||||||
|
printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x01\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x01\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' \
|
||||||
|
> functions/hid.usb1/report_desc
|
||||||
|
|
||||||
# # -- UAC2 Audio
|
# # -- UAC2 Audio
|
||||||
# mkdir -p $G/functions/uac2.usb0
|
# mkdir -p $G/functions/uac2.usb0
|
||||||
# echo 48000 > $G/functions/uac2.usb0/c_srate
|
# echo 48000 > $G/functions/uac2.usb0/c_srate
|
||||||
|
|||||||
@ -13,10 +13,20 @@ use navka_common::navka::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Handler {
|
struct Handler {
|
||||||
/// shared async handle to /dev/hidg0
|
kb: Arc<Mutex<File>>,
|
||||||
hid: Arc<tokio::sync::Mutex<tokio::fs::File>>,
|
ms: Arc<Mutex<File>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let kb = OpenOptions::new().write(true).read(true)
|
||||||
|
.custom_flags(libc::O_NONBLOCK)
|
||||||
|
.open("/dev/hidg0").await?;
|
||||||
|
let ms = OpenOptions::new().write(true).read(true)
|
||||||
|
.custom_flags(libc::O_NONBLOCK)
|
||||||
|
.open("/dev/hidg1").await?;
|
||||||
|
|
||||||
|
let handler = Handler { kb: Arc::new(Mutex::new(kb)),
|
||||||
|
ms: Arc::new(Mutex::new(ms)) };
|
||||||
|
|
||||||
#[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
impl Relay for Handler {
|
impl Relay for Handler {
|
||||||
type StreamStream =
|
type StreamStream =
|
||||||
@ -32,16 +42,21 @@ impl Relay for Handler {
|
|||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(msg) = in_stream.next().await.transpose()? {
|
while let Some(msg) = in_stream.next().await.transpose()? {
|
||||||
let data = msg.data.get(..8).ok_or_else(|| Status::invalid_argument("short"))?;
|
match msg.kind {
|
||||||
{
|
Some(navka::hid_report::Kind::KeyboardReport(ref v)) if v.len() == 8 => {
|
||||||
let mut f = hid.lock().await;
|
let mut f = kb.lock().await;
|
||||||
if let Err(e) = f.write_all(data).await {
|
f.write_all(v).await?;
|
||||||
error!("USB write failed: {e}");
|
|
||||||
return Err(Status::internal(e.to_string()));
|
|
||||||
}
|
}
|
||||||
f.flush().await.ok();
|
Some(navka::hid_report::Kind::MouseReport(ref v)) if v.len() == 4 => {
|
||||||
|
let mut f = ms.lock().await;
|
||||||
|
f.write_all(v).await?;
|
||||||
}
|
}
|
||||||
info!(bytes=?data, len=data.len(), "HID report received");
|
_ => {
|
||||||
|
error!("bad packet len={}", msg.data.len());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("HID report forwarded");
|
||||||
let _ = tx.send(Ok(msg)).await;
|
let _ = tx.send(Ok(msg)).await;
|
||||||
}
|
}
|
||||||
Ok::<_, Status>(())
|
Ok::<_, Status>(())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user