@desklink/host 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/NOTICE +3 -0
  2. package/README.md +92 -23
  3. package/bin/desklink-host.mjs +14 -5
  4. package/dist/bridge.d.ts +3 -4
  5. package/dist/bridge.d.ts.map +1 -1
  6. package/dist/bridge.js +18 -7
  7. package/dist/bridge.js.map +1 -1
  8. package/dist/engineProcess.d.ts +6 -1
  9. package/dist/engineProcess.d.ts.map +1 -1
  10. package/dist/engineProcess.js +34 -5
  11. package/dist/engineProcess.js.map +1 -1
  12. package/dist/protocol.d.ts +35 -2
  13. package/dist/protocol.d.ts.map +1 -1
  14. package/dist/protocol.js.map +1 -1
  15. package/dist/resolveEngine.d.ts +6 -0
  16. package/dist/resolveEngine.d.ts.map +1 -1
  17. package/dist/resolveEngine.js +45 -6
  18. package/dist/resolveEngine.js.map +1 -1
  19. package/docs/BOUNDARY.md +8 -8
  20. package/docs/PROTOCOL.md +185 -45
  21. package/engine/Cargo.lock +2 -2
  22. package/engine/Cargo.toml +7 -12
  23. package/engine/build.rs +62 -5
  24. package/engine/native/agent_indicator.h +57 -0
  25. package/engine/native/agent_overlay_mac.m +51 -4
  26. package/engine/native/agent_overlay_wayland.c +189 -35
  27. package/engine/native/agent_overlay_x11.c +186 -55
  28. package/engine/src/capture.rs +96 -5
  29. package/engine/src/capture_win.rs +23 -0
  30. package/engine/src/clipboard.rs +174 -0
  31. package/engine/src/clipboard_win.rs +8 -0
  32. package/engine/src/cursor.rs +118 -0
  33. package/engine/src/indicator.rs +271 -5
  34. package/engine/src/input_win.rs +91 -0
  35. package/engine/src/keymap_win.rs +39 -0
  36. package/engine/src/mac.rs +28 -6
  37. package/engine/src/main.rs +167 -25
  38. package/engine/src/peer.rs +10 -4
  39. package/engine/src/portal.rs +42 -4
  40. package/engine/src/portal_win.rs +37 -0
  41. package/engine/src/protocol.rs +56 -10
  42. package/engine/src/session.rs +749 -203
  43. package/engine/src/win.rs +110 -0
  44. package/engine/src/x11.rs +44 -29
  45. package/engine/src/x11_mac.rs +4 -0
  46. package/examples/reference-client.html +3 -5
  47. package/package.json +4 -4
@@ -0,0 +1,37 @@
1
+ use anyhow::{bail, Result};
2
+ use serde_json::Value;
3
+
4
+ /// A selected display; Windows enumeration is deferred to the capture lane.
5
+ #[derive(Debug, Clone, serde::Serialize)]
6
+ pub struct SelectedSource {
7
+ pub node_id: u32,
8
+ pub width: i32,
9
+ pub height: i32,
10
+ #[serde(skip_serializing_if = "Option::is_none")]
11
+ pub position: Option<(i32, i32)>,
12
+ #[serde(skip_serializing_if = "Option::is_none")]
13
+ pub source_type: Option<String>,
14
+ pub origin_x: i32,
15
+ pub origin_y: i32,
16
+ }
17
+
18
+ pub struct PortalSession {
19
+ pub source: SelectedSource,
20
+ pub restore_token: Option<String>,
21
+ }
22
+
23
+ pub async fn open(_restore_token: Option<&str>) -> Result<PortalSession> {
24
+ open_display_inner(None)
25
+ }
26
+
27
+ pub async fn open_display(display_id: Option<u32>) -> Result<PortalSession> {
28
+ open_display_inner(display_id)
29
+ }
30
+
31
+ fn open_display_inner(_display_id: Option<u32>) -> Result<PortalSession> {
32
+ bail!("{}", crate::capture::unavailable_reason())
33
+ }
34
+
35
+ pub fn displays() -> Vec<Value> {
36
+ Vec::new()
37
+ }
@@ -53,14 +53,6 @@ pub struct HelloParams {
53
53
  pub protocol: u32,
54
54
  }
55
55
 
56
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
57
- #[serde(rename_all = "snake_case")]
58
- pub enum Permission {
59
- View,
60
- Control,
61
- Clipboard,
62
- }
63
-
64
56
  #[derive(Debug, Clone, Deserialize)]
65
57
  pub struct IceServerParam {
66
58
  #[serde(default)]
@@ -111,13 +103,21 @@ pub enum EncodedCodec {
111
103
  H264,
112
104
  }
113
105
 
106
+ #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
107
+ #[serde(rename_all = "snake_case")]
108
+ pub enum CursorMode {
109
+ #[default]
110
+ Embedded,
111
+ Hidden,
112
+ }
113
+
114
114
  #[derive(Debug, Deserialize)]
115
115
  pub struct OpenParams {
116
+ #[serde(default)]
117
+ pub cursor: CursorMode,
116
118
  /// Absent means "the portal, with the user's consent".
117
119
  #[serde(default)]
118
120
  pub source: Option<SourceRequest>,
119
- #[serde(default)]
120
- pub permissions: Vec<Permission>,
121
121
  #[serde(default = "default_max_width")]
122
122
  pub max_width: usize,
123
123
  #[serde(default = "default_max_height")]
@@ -168,6 +168,20 @@ fn default_fps() -> u32 {
168
168
  60
169
169
  }
170
170
 
171
+ /// A host-only visual cue; never an input message.
172
+ #[derive(Debug, Deserialize)]
173
+ #[serde(deny_unknown_fields)]
174
+ pub struct PointParams {
175
+ pub session_id: String,
176
+ pub x: Option<i64>,
177
+ pub y: Option<i64>,
178
+ #[serde(default)]
179
+ pub label: String,
180
+ pub timeout_ms: Option<u64>,
181
+ #[serde(default)]
182
+ pub clear: bool,
183
+ }
184
+
171
185
  #[derive(Debug, Deserialize)]
172
186
  pub struct FrameParams {
173
187
  pub session_id: String,
@@ -385,6 +399,16 @@ pub enum ControlReply<'a> {
385
399
  mod tests {
386
400
  use super::*;
387
401
 
402
+ #[test]
403
+ fn cursor_option_defaults_and_refuses_unknown_modes() {
404
+ let default: OpenParams = serde_json::from_str("{}").unwrap();
405
+ assert_eq!(default.cursor, CursorMode::Embedded);
406
+ let hidden: OpenParams = serde_json::from_str(r#"{"cursor":"hidden"}"#).unwrap();
407
+ assert_eq!(hidden.cursor, CursorMode::Hidden);
408
+ assert!(serde_json::from_str::<OpenParams>(r#"{"cursor":"metadata"}"#).is_err());
409
+ assert!(serde_json::from_str::<OpenParams>(r#"{"cursor":false}"#).is_err());
410
+ }
411
+
388
412
  #[test]
389
413
  fn a_pointer_message_round_trips_with_its_sequence() {
390
414
  let parsed: ControlMessage =
@@ -505,6 +529,13 @@ mod tests {
505
529
 
506
530
  #[test]
507
531
  fn open_defaults_keep_the_desktops_own_pixels_up_to_4k() {
532
+ for payload in [
533
+ r#"{}"#,
534
+ r#"{"permissions":["view"]}"#,
535
+ r#"{"permissions":["view","unknown-legacy-scope"]}"#,
536
+ ] {
537
+ let _: OpenParams = serde_json::from_str(payload).unwrap();
538
+ }
508
539
  let params: OpenParams =
509
540
  serde_json::from_str(r#"{"permissions":["view","control"]}"#).unwrap();
510
541
  assert_eq!(params.max_width, 3840);
@@ -525,3 +556,18 @@ mod tests {
525
556
  assert!(agent.agent_indicator);
526
557
  }
527
558
  }
559
+
560
+ /// Monotonic engine-process clock shared by local frame and cursor notices.
561
+ pub fn timestamp_us(at: std::time::Instant) -> u64 {
562
+ static EPOCH: std::sync::OnceLock<std::time::Instant> = std::sync::OnceLock::new();
563
+ at.saturating_duration_since(*EPOCH.get_or_init(|| at))
564
+ .as_micros() as u64
565
+ }
566
+
567
+ #[derive(Debug, Clone, Copy)]
568
+ pub struct CursorPosition {
569
+ pub x: i32,
570
+ pub y: i32,
571
+ pub visible: bool,
572
+ pub timestamp_us: u64,
573
+ }