cursor-mover-app/crates/cursor-mover-webapp/src/components/controls.rs

129 lines
3.9 KiB
Rust
Raw Normal View History

2026-03-03 17:46:51 +01:00
use dioxus::{
fullstack::{CborEncoding, WebSocketOptions, Websocket, extract::State, use_websocket},
2026-03-03 18:08:02 +01:00
html::input_data::MouseButton,
2026-03-03 17:46:51 +01:00
logger::tracing,
prelude::*,
};
use serde::{Deserialize, Serialize};
use crate::components::{KeyboardArea, MouseArea};
#[component]
pub fn Controls() -> Element {
#[css_module("/assets/styling/controls.module.css")]
struct Styles;
2026-03-03 21:38:18 +01:00
let mut socket = use_websocket(move || remote_control(WebSocketOptions::new()));
2026-03-03 17:46:51 +01:00
use_future(move || async move {
loop {
// Wait for the socket to connect
_ = socket.connect().await;
// Loop poll with recv. Throws an error when the connection closes, making it possible
// to run code before the socket re-connects when the name input changes
while let Ok(message) = socket.recv().await {
tracing::info!("Received message: {:?}", message);
}
}
});
let event_handler = use_callback(move |evt| {
spawn(async move {
_ = socket.send(evt).await;
});
});
2026-03-03 21:38:18 +01:00
match *socket.status().read() {
dioxus_fullstack::WebsocketState::Connecting => {
rsx! {
div {
"Connecting..."
}
}
},
dioxus_fullstack::WebsocketState::Open => {
rsx! {
div {
class: Styles::controls,
MouseArea { onevent: event_handler }
KeyboardArea { onevent: event_handler }
}
}
},
dioxus_fullstack::WebsocketState::Closing => {
rsx! {
div {
"Closing..."
}
}
},
dioxus_fullstack::WebsocketState::Closed => {
rsx! {
div {
"Closed..."
}
}
},
dioxus_fullstack::WebsocketState::FailedToConnect => {
rsx! {
div {
"Failed to connect..."
}
}
},
2026-03-03 17:46:51 +01:00
}
}
#[derive(Serialize, Deserialize, Debug)]
pub enum ClientEvent {
MouseMove { dx: f64, dy: f64 },
MouseScroll { dx: f64, dy: f64 },
Click { button: MouseButton },
KeyPressEvent { key: String },
TextInputStartEvent,
TextInputEvent { text: String },
TextInputDoneEvent { text: String },
}
#[derive(Serialize, Deserialize, Debug)]
enum ServerEvent {
Ping,
}
#[expect(clippy::unused_async)]
2026-03-03 21:38:18 +01:00
#[get("/api/remote_control_wss", mouse_service: State<crate::server::input_proxy_service::InputProxyService>)]
async fn remote_control(
2026-03-03 17:46:51 +01:00
options: WebSocketOptions
) -> Result<Websocket<ClientEvent, ServerEvent, CborEncoding>> {
Ok(options.on_upgrade(move |mut socket| async move {
_ = socket.send(ServerEvent::Ping).await;
while let Ok(event) = socket.recv().await {
match event {
ClientEvent::MouseMove { dx, dy } => {
mouse_service.move_mouse(dx, dy).await;
},
ClientEvent::MouseScroll { dx, dy } => {
mouse_service.mouse_scroll(dx, dy).await;
},
ClientEvent::Click { button } => {
mouse_service.click(button).await;
},
ClientEvent::KeyPressEvent { key } => {
mouse_service.key_press_event(key).await;
},
ClientEvent::TextInputEvent { text } => {
mouse_service.text_input(text).await;
},
ClientEvent::TextInputStartEvent => {
mouse_service.text_input_start().await;
},
ClientEvent::TextInputDoneEvent { text } => {
mouse_service.text_input_end(text).await;
},
}
}
}))
}