diff --git a/Cargo.lock b/Cargo.lock index a359ce6..1d8c8e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -632,7 +632,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -806,9 +818,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "lighthouse-client" -version = "3.4.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6056da3ea5337105f7e69df5678c4240ec14ac912a03cd93f86f8075f27b0ce0" +checksum = "b45cbc92c5f1bc3bec7f803f9b8b41480a9b4ca2e4b680ed1cf8826417781960" dependencies = [ "async-tungstenite", "futures", @@ -825,9 +837,9 @@ dependencies = [ [[package]] name = "lighthouse-protocol" -version = "3.4.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "574e8a8c3ea53dbb741f7a8ac0ebd918c9b72bd278f37b5b61bef997cabdc23b" +checksum = "6697f71915df7d895bb21968c8bd81eeb759e3f03ab8d6b633c8ef29ed67b44c" dependencies = [ "rand", "rmpv", @@ -848,12 +860,14 @@ dependencies = [ "futures", "lighthouse-client", "multipeek", + "once_cell", "ratatui", "ref-cast", "rustyline", "serde_json", "tokio", "url", + "uuid", ] [[package]] @@ -910,7 +924,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -922,7 +936,7 @@ checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ "hermit-abi", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -996,9 +1010,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "openssl" @@ -1184,7 +1198,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -1801,6 +1815,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -1819,6 +1842,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -2043,6 +2075,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 0edac72..8bba465 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,13 @@ colored = "2.1.0" crossterm = { version = "0.27.0", features = ["event-stream"] } dotenvy = "0.15" futures = "0.3.30" -lighthouse-client = "3.4.0" +lighthouse-client = "5.0.1" multipeek = "0.1.2" +once_cell = "1.20.3" ratatui = "0.27.0" ref-cast = "1.0" rustyline = "14.0" serde_json = "1.0.114" tokio = { version = "1.36.0", features = ["macros", "rt-multi-thread", "time", "fs"] } url = "2.5.0" +uuid = { version = "1.15.1", features = ["v4"] } diff --git a/src/client_id.rs b/src/client_id.rs new file mode 100644 index 0000000..6c91aec --- /dev/null +++ b/src/client_id.rs @@ -0,0 +1,5 @@ +use once_cell::sync::Lazy; +use uuid::Uuid; + +/// This client's unique id. +pub const CLIENT_ID: Lazy = Lazy::new(|| Uuid::new_v4()); diff --git a/src/cmd/display.rs b/src/cmd/display.rs index 102906c..facce49 100644 --- a/src/cmd/display.rs +++ b/src/cmd/display.rs @@ -1,9 +1,9 @@ -use crate::{context::Context, path::VirtualPathBuf}; +use crate::{client_id::CLIENT_ID, context::Context, path::VirtualPathBuf}; use anyhow::Result; use clap::{command, Parser}; use crossterm::event::{Event, EventStream, KeyCode, KeyEventKind}; use futures::{select, StreamExt}; -use lighthouse_client::protocol::{Frame, InputEvent, Model, LIGHTHOUSE_COLS, LIGHTHOUSE_ROWS}; +use lighthouse_client::protocol::{EventSource, Frame, InputEvent, KeyEvent, KeyModifiers, LegacyInputEvent, Model, LIGHTHOUSE_COLS, LIGHTHOUSE_ROWS}; use ratatui::{ backend::CrosstermBackend, crossterm::{ @@ -25,6 +25,9 @@ const QUIT_KEY: char = 'q'; #[derive(Parser)] #[command(bin_name = "display")] struct Args { + #[arg(short, long, action, help = "Generate legacy input events")] + legacy: bool, + #[arg( default_value = ".", help = "The resource to display as an image stream" @@ -48,14 +51,29 @@ pub async fn invoke(args: &[String], ctx: &mut Context) -> Result { msg = reader.next() => match msg { Some(Ok(Event::Key(e))) => match e.code { KeyCode::Char(QUIT_KEY) => break, - _ => if let Some(code) = key_code_to_js(e.code) { - ctx.lh.put(&path.as_lh_vec(), Model::InputEvent(InputEvent { - source: 0, - key: Some(code), - button: None, - is_down: matches!(e.kind, KeyEventKind::Press | KeyEventKind::Repeat), - })).await?; - } + _ => { + let down = matches!(e.kind, KeyEventKind::Press | KeyEventKind::Repeat); + if args.legacy { + if let Some(code) = key_code_to_js_key_code(e.code) { + ctx.lh.put(&path.as_lh_vec(), Model::InputEvent(LegacyInputEvent { + source: 0, + key: Some(code), + button: None, + is_down: down, + })).await?; + } + } else { + if let Some(code) = key_code_to_js_code(e.code) { + ctx.lh.put_input(InputEvent::Key(KeyEvent { + source: EventSource::String(format!("limo:{}", *CLIENT_ID)), + code, + down, + repeat: matches!(e.kind, KeyEventKind::Repeat), + modifiers: KeyModifiers::default(), + })).await?; + } + } + }, }, None | Some(Err(_)) => break, _ => {}, @@ -78,8 +96,6 @@ pub async fn invoke(args: &[String], ctx: &mut Context) -> Result { stdout().execute(LeaveAlternateScreen)?; disable_raw_mode()?; - ctx.lh.stop(&path.as_lh_vec()).await?; - Ok(String::new()) } @@ -151,7 +167,7 @@ impl Shape for Display { } } -fn key_code_to_js(key_code: KeyCode) -> Option { +fn key_code_to_js_key_code(key_code: KeyCode) -> Option { match key_code { KeyCode::Backspace => Some(8), KeyCode::Enter => Some(13), @@ -177,3 +193,28 @@ fn key_code_to_js(key_code: KeyCode) -> Option { _ => None, } } + +fn key_code_to_js_code(key_code: KeyCode) -> Option { + match key_code { + KeyCode::Backspace => Some("Backspace".into()), + KeyCode::Enter => Some("Enter".into()), + KeyCode::Left => Some("ArrowLeft".into()), + KeyCode::Right => Some("ArrowRight".into()), + KeyCode::Up => Some("ArrowUp".into()), + KeyCode::Down => Some("ArrowDown".into()), + KeyCode::Home => Some("Home".into()), + KeyCode::End => Some("End".into()), + KeyCode::PageUp => Some("PageUp".into()), + KeyCode::PageDown => Some("PageDown".into()), + KeyCode::Tab => Some("Tab".into()), + KeyCode::Delete => Some("Delete".into()), + KeyCode::Insert => Some("Insert".into()), + KeyCode::F(n) => Some(format!("F{n}")), + KeyCode::Char(c) if c.is_ascii_digit() => Some(format!("Digit{c}")), + KeyCode::Char(c) => Some(format!("Key{c}")), + KeyCode::Esc => Some("Escape".into()), + KeyCode::CapsLock => Some("CapsLock".into()), + KeyCode::NumLock => Some("NumLock".into()), + _ => None, + } +} diff --git a/src/main.rs b/src/main.rs index 322f7df..369c1e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod cmd; +mod client_id; mod context; mod line; mod path;