@desklink/host 0.2.0 → 0.3.1
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.
- package/NOTICE +26 -0
- package/README.md +134 -56
- package/bin/desklink-host.mjs +13 -5
- package/dist/bridge.d.ts +1 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +12 -4
- package/dist/bridge.js.map +1 -1
- package/dist/engineProcess.d.ts +6 -1
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +35 -4
- package/dist/engineProcess.js.map +1 -1
- package/dist/protocol.d.ts +58 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/resolveEngine.d.ts +7 -1
- package/dist/resolveEngine.d.ts.map +1 -1
- package/dist/resolveEngine.js +66 -14
- package/dist/resolveEngine.js.map +1 -1
- package/docs/BOUNDARY.md +15 -7
- package/docs/PROTOCOL.md +267 -27
- package/engine/Cargo.lock +47 -2
- package/engine/Cargo.toml +18 -13
- package/engine/build.rs +86 -4
- package/engine/native/agent_overlay_mac.m +51 -4
- package/engine/native/agent_overlay_wayland.c +145 -12
- package/engine/native/agent_overlay_x11.c +72 -0
- package/engine/native/nvenc_shim.c +453 -0
- package/engine/native/vaapi_shim.c +727 -0
- package/engine/native/vpx_shim.c +54 -4
- package/engine/native/vt_shim.c +448 -0
- package/engine/src/capture.rs +167 -58
- package/engine/src/capture_mac.rs +24 -14
- package/engine/src/capture_win.rs +23 -0
- package/engine/src/clipboard_win.rs +8 -0
- package/engine/src/convert.rs +286 -61
- package/engine/src/cursor.rs +118 -0
- package/engine/src/encoder.rs +122 -13
- package/engine/src/h264.rs +188 -0
- package/engine/src/h264_nvenc.rs +308 -0
- package/engine/src/h264_openh264.rs +735 -0
- package/engine/src/h264_vaapi.rs +263 -0
- package/engine/src/h264_vt.rs +368 -0
- package/engine/src/indicator.rs +104 -3
- package/engine/src/input_win.rs +91 -0
- package/engine/src/keymap_win.rs +39 -0
- package/engine/src/mac.rs +34 -9
- package/engine/src/main.rs +186 -26
- package/engine/src/peer.rs +466 -28
- package/engine/src/portal.rs +42 -4
- package/engine/src/portal_win.rs +37 -0
- package/engine/src/protocol.rs +64 -2
- package/engine/src/session.rs +1252 -105
- package/engine/src/win.rs +110 -0
- package/engine/src/x11.rs +225 -9
- package/engine/src/x11_mac.rs +12 -0
- package/engine/vendor/libva/COPYING +19 -0
- package/engine/vendor/libva/va/va.h +5450 -0
- package/engine/vendor/libva/va/va_dec_av1.h +695 -0
- package/engine/vendor/libva/va/va_dec_hevc.h +616 -0
- package/engine/vendor/libva/va/va_dec_jpeg.h +157 -0
- package/engine/vendor/libva/va/va_dec_vp8.h +249 -0
- package/engine/vendor/libva/va/va_dec_vp9.h +312 -0
- package/engine/vendor/libva/va/va_dec_vvc.h +688 -0
- package/engine/vendor/libva/va/va_drm.h +61 -0
- package/engine/vendor/libva/va/va_enc_av1.h +1010 -0
- package/engine/vendor/libva/va/va_enc_h264.h +659 -0
- package/engine/vendor/libva/va/va_enc_hevc.h +958 -0
- package/engine/vendor/libva/va/va_enc_jpeg.h +162 -0
- package/engine/vendor/libva/va/va_enc_mpeg2.h +308 -0
- package/engine/vendor/libva/va/va_enc_vp8.h +350 -0
- package/engine/vendor/libva/va/va_enc_vp9.h +639 -0
- package/engine/vendor/libva/va/va_fei.h +170 -0
- package/engine/vendor/libva/va/va_fei_h264.h +505 -0
- package/engine/vendor/libva/va/va_fei_hevc.h +254 -0
- package/engine/vendor/libva/va/va_prot.h +525 -0
- package/engine/vendor/libva/va/va_version.h +87 -0
- package/engine/vendor/libva/va/va_vpp.h +1590 -0
- package/engine/vendor/nv-codec-headers/LICENSE +24 -0
- package/engine/vendor/nv-codec-headers/README +7 -0
- package/engine/vendor/nv-codec-headers/include/ffnvcodec/nvEncodeAPI.h +3825 -0
- package/examples/reference-client.html +1 -1
- package/package.json +4 -3
package/engine/src/main.rs
CHANGED
|
@@ -11,24 +11,51 @@ mod capture;
|
|
|
11
11
|
#[cfg(target_os = "macos")]
|
|
12
12
|
#[path = "capture_mac.rs"]
|
|
13
13
|
mod capture;
|
|
14
|
+
#[cfg(target_os = "windows")]
|
|
15
|
+
#[path = "capture_win.rs"]
|
|
16
|
+
mod capture;
|
|
14
17
|
#[cfg(target_os = "linux")]
|
|
15
18
|
mod clipboard;
|
|
16
19
|
#[cfg(target_os = "macos")]
|
|
17
20
|
#[path = "clipboard_mac.rs"]
|
|
18
21
|
mod clipboard;
|
|
19
|
-
#[cfg(
|
|
22
|
+
#[cfg(target_os = "windows")]
|
|
23
|
+
#[path = "clipboard_win.rs"]
|
|
24
|
+
mod clipboard;
|
|
25
|
+
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
|
20
26
|
mod convert;
|
|
21
27
|
#[cfg(target_os = "linux")]
|
|
28
|
+
mod cursor;
|
|
29
|
+
#[cfg(target_os = "linux")]
|
|
22
30
|
mod encoder;
|
|
23
|
-
#[cfg(all(target_os = "macos", desklink_vpx))]
|
|
31
|
+
#[cfg(all(any(target_os = "macos", target_os = "windows"), desklink_vpx))]
|
|
24
32
|
mod encoder;
|
|
25
|
-
#[cfg(any(
|
|
33
|
+
#[cfg(any(
|
|
34
|
+
target_os = "linux",
|
|
35
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
36
|
+
))]
|
|
37
|
+
mod h264;
|
|
38
|
+
#[cfg(target_os = "linux")]
|
|
39
|
+
mod h264_nvenc;
|
|
40
|
+
#[cfg(target_os = "linux")]
|
|
41
|
+
mod h264_openh264;
|
|
42
|
+
#[cfg(target_os = "linux")]
|
|
43
|
+
mod h264_vaapi;
|
|
44
|
+
#[cfg(all(target_os = "macos", desklink_vpx))]
|
|
45
|
+
mod h264_vt;
|
|
46
|
+
#[cfg(any(
|
|
47
|
+
target_os = "linux",
|
|
48
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
49
|
+
))]
|
|
26
50
|
mod indicator;
|
|
27
51
|
#[cfg(target_os = "linux")]
|
|
28
52
|
mod input;
|
|
29
53
|
#[cfg(target_os = "macos")]
|
|
30
54
|
#[path = "input_mac.rs"]
|
|
31
55
|
mod input;
|
|
56
|
+
#[cfg(target_os = "windows")]
|
|
57
|
+
#[path = "input_win.rs"]
|
|
58
|
+
mod input;
|
|
32
59
|
#[cfg(target_os = "linux")]
|
|
33
60
|
mod keeper;
|
|
34
61
|
#[cfg(target_os = "linux")]
|
|
@@ -36,44 +63,76 @@ mod keymap;
|
|
|
36
63
|
#[cfg(target_os = "macos")]
|
|
37
64
|
#[path = "keymap_mac.rs"]
|
|
38
65
|
mod keymap;
|
|
66
|
+
#[cfg(target_os = "windows")]
|
|
67
|
+
#[path = "keymap_win.rs"]
|
|
68
|
+
mod keymap;
|
|
39
69
|
#[cfg(target_os = "macos")]
|
|
40
70
|
mod mac;
|
|
41
|
-
#[cfg(any(
|
|
71
|
+
#[cfg(any(
|
|
72
|
+
target_os = "linux",
|
|
73
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
74
|
+
))]
|
|
42
75
|
mod peer;
|
|
43
76
|
#[cfg(target_os = "linux")]
|
|
44
77
|
mod portal;
|
|
45
78
|
#[cfg(target_os = "macos")]
|
|
46
79
|
#[path = "portal_mac.rs"]
|
|
47
80
|
mod portal;
|
|
48
|
-
#[cfg(
|
|
81
|
+
#[cfg(target_os = "windows")]
|
|
82
|
+
#[path = "portal_win.rs"]
|
|
83
|
+
mod portal;
|
|
84
|
+
#[cfg(any(
|
|
85
|
+
target_os = "linux",
|
|
86
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
87
|
+
))]
|
|
49
88
|
mod protocol;
|
|
50
89
|
#[cfg(target_os = "linux")]
|
|
51
90
|
mod session;
|
|
52
|
-
#[cfg(all(target_os = "macos", desklink_vpx))]
|
|
91
|
+
#[cfg(all(any(target_os = "macos", target_os = "windows"), desklink_vpx))]
|
|
53
92
|
mod session;
|
|
93
|
+
#[cfg(target_os = "windows")]
|
|
94
|
+
mod win;
|
|
54
95
|
#[cfg(target_os = "linux")]
|
|
55
96
|
mod x11;
|
|
56
|
-
#[cfg(target_os = "macos")]
|
|
97
|
+
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
|
57
98
|
#[path = "x11_mac.rs"]
|
|
58
99
|
mod x11;
|
|
59
100
|
|
|
60
|
-
#[cfg(any(
|
|
101
|
+
#[cfg(any(
|
|
102
|
+
target_os = "linux",
|
|
103
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
104
|
+
))]
|
|
61
105
|
use anyhow::Result;
|
|
62
|
-
#[cfg(any(
|
|
106
|
+
#[cfg(any(
|
|
107
|
+
target_os = "linux",
|
|
108
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
109
|
+
))]
|
|
63
110
|
use protocol::{ErrorBody, Event, Request, Response};
|
|
64
111
|
#[cfg(target_os = "linux")]
|
|
65
112
|
use std::sync::mpsc as std_mpsc;
|
|
66
|
-
#[cfg(any(
|
|
113
|
+
#[cfg(any(
|
|
114
|
+
target_os = "linux",
|
|
115
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
116
|
+
))]
|
|
67
117
|
use std::time::Duration;
|
|
68
|
-
#[cfg(any(
|
|
118
|
+
#[cfg(any(
|
|
119
|
+
target_os = "linux",
|
|
120
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
121
|
+
))]
|
|
69
122
|
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
|
70
|
-
#[cfg(any(
|
|
123
|
+
#[cfg(any(
|
|
124
|
+
target_os = "linux",
|
|
125
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
126
|
+
))]
|
|
71
127
|
use tokio::sync::mpsc as tokio_mpsc;
|
|
72
128
|
|
|
73
129
|
#[cfg(target_os = "linux")]
|
|
74
130
|
unsafe extern "C" {
|
|
131
|
+
fn desklink_point_overlay_main(display: *const std::ffi::c_char) -> i32;
|
|
75
132
|
fn desklink_agent_overlay_main(display: *const std::ffi::c_char) -> i32;
|
|
76
133
|
fn desklink_agent_overlay_wayland(source_w: i32, source_h: i32) -> i32;
|
|
134
|
+
fn desklink_wayland_layer_shell_available() -> i32;
|
|
135
|
+
fn desklink_point_overlay_wayland(w: i32, h: i32, known: i32, x: i32, y: i32) -> i32;
|
|
77
136
|
}
|
|
78
137
|
|
|
79
138
|
#[cfg(target_os = "linux")]
|
|
@@ -95,11 +154,39 @@ fn main() {
|
|
|
95
154
|
println!("{}", env!("CARGO_PKG_VERSION"));
|
|
96
155
|
0
|
|
97
156
|
}
|
|
157
|
+
"point-overlay" => {
|
|
158
|
+
let display = args.get(1).map(String::as_str).unwrap_or("");
|
|
159
|
+
let display = std::ffi::CString::new(display).expect("valid X display");
|
|
160
|
+
unsafe { desklink_point_overlay_main(display.as_ptr()) }
|
|
161
|
+
}
|
|
98
162
|
"agent-overlay" => {
|
|
99
163
|
let display = args.get(1).map(String::as_str).unwrap_or("");
|
|
100
164
|
let display = std::ffi::CString::new(display).expect("valid X display");
|
|
101
165
|
unsafe { desklink_agent_overlay_main(display.as_ptr()) }
|
|
102
166
|
}
|
|
167
|
+
"point-layer-shell-probe" => match unsafe { desklink_wayland_layer_shell_available() } {
|
|
168
|
+
1 => {
|
|
169
|
+
println!("READY");
|
|
170
|
+
0
|
|
171
|
+
}
|
|
172
|
+
0 => {
|
|
173
|
+
println!("layer_shell_unavailable");
|
|
174
|
+
2
|
|
175
|
+
}
|
|
176
|
+
_ => 2,
|
|
177
|
+
},
|
|
178
|
+
"point-overlay-wayland" => {
|
|
179
|
+
let values: Vec<i32> = args.iter().skip(1).filter_map(|v| v.parse().ok()).collect();
|
|
180
|
+
if values.len() != 5 || values[0] <= 0 || values[1] <= 0 {
|
|
181
|
+
2
|
|
182
|
+
} else {
|
|
183
|
+
unsafe {
|
|
184
|
+
desklink_point_overlay_wayland(
|
|
185
|
+
values[0], values[1], values[2], values[3], values[4],
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
103
190
|
"agent-overlay-wayland" => {
|
|
104
191
|
let width = args.get(1).and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
105
192
|
let height = args.get(2).and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
@@ -139,7 +226,10 @@ fn main() {
|
|
|
139
226
|
std::process::exit(code);
|
|
140
227
|
}
|
|
141
228
|
|
|
142
|
-
#[cfg(any(
|
|
229
|
+
#[cfg(any(
|
|
230
|
+
target_os = "linux",
|
|
231
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
232
|
+
))]
|
|
143
233
|
fn report(result: Result<()>) -> i32 {
|
|
144
234
|
match result {
|
|
145
235
|
Ok(()) => 0,
|
|
@@ -285,15 +375,23 @@ fn frame_shape(frame: &crate::convert::I420) -> u64 {
|
|
|
285
375
|
|
|
286
376
|
#[cfg(target_os = "linux")]
|
|
287
377
|
async fn probe_portal(seconds: u64) -> Result<()> {
|
|
288
|
-
let portal = portal::open(None).await?;
|
|
378
|
+
let portal = portal::open(None, protocol::CursorMode::Embedded).await?;
|
|
289
379
|
eprintln!("portal source: {:?}", portal.source);
|
|
380
|
+
// The source's own size: a zero box converts nothing and reports no frames.
|
|
381
|
+
let (width, height) = crate::convert::fit(
|
|
382
|
+
portal.source.width.max(0) as usize,
|
|
383
|
+
portal.source.height.max(0) as usize,
|
|
384
|
+
usize::MAX,
|
|
385
|
+
usize::MAX,
|
|
386
|
+
);
|
|
290
387
|
|
|
291
388
|
let (tx, rx) = std_mpsc::channel();
|
|
292
389
|
let capture = capture::start(
|
|
293
390
|
portal,
|
|
294
|
-
|
|
295
|
-
|
|
391
|
+
width,
|
|
392
|
+
height,
|
|
296
393
|
30,
|
|
394
|
+
None,
|
|
297
395
|
Box::new(move |frame, seq, _raw| {
|
|
298
396
|
let _ = tx.send((frame.width, frame.height, seq));
|
|
299
397
|
}),
|
|
@@ -332,7 +430,10 @@ async fn probe_portal(seconds: u64) -> Result<()> {
|
|
|
332
430
|
}
|
|
333
431
|
|
|
334
432
|
/// The local control protocol loop.
|
|
335
|
-
#[cfg(any(
|
|
433
|
+
#[cfg(any(
|
|
434
|
+
target_os = "linux",
|
|
435
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
436
|
+
))]
|
|
336
437
|
async fn serve() -> Result<()> {
|
|
337
438
|
let (out_tx, mut out_rx) = tokio_mpsc::unbounded_channel::<String>();
|
|
338
439
|
let writer = tokio::spawn(async move {
|
|
@@ -417,13 +518,16 @@ async fn serve() -> Result<()> {
|
|
|
417
518
|
if let Some(session) = current.take() {
|
|
418
519
|
session.close("the consumer disconnected").await;
|
|
419
520
|
}
|
|
420
|
-
|
|
521
|
+
drop(events_tx);
|
|
421
522
|
drop(out_tx);
|
|
422
523
|
let _ = writer.await;
|
|
423
524
|
Ok(())
|
|
424
525
|
}
|
|
425
526
|
|
|
426
|
-
#[cfg(any(
|
|
527
|
+
#[cfg(any(
|
|
528
|
+
target_os = "linux",
|
|
529
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
530
|
+
))]
|
|
427
531
|
fn render_event(notice: session::Notice) -> Option<String> {
|
|
428
532
|
let session::Notice { session_id, event } = notice;
|
|
429
533
|
let (name, params) = match event {
|
|
@@ -454,9 +558,17 @@ fn render_event(notice: session::Notice) -> Option<String> {
|
|
|
454
558
|
"session.state",
|
|
455
559
|
serde_json::json!({ "sessionId": session_id, "capture": capture, "transport": transport, "firstFrame": first_frame }),
|
|
456
560
|
),
|
|
457
|
-
session::SessionEvent::
|
|
561
|
+
session::SessionEvent::Cursor { position } => (
|
|
562
|
+
"session.cursor",
|
|
563
|
+
serde_json::json!({ "sessionId": session_id, "x": position.x, "y": position.y, "visible": position.visible, "timestamp_us": position.timestamp_us }),
|
|
564
|
+
),
|
|
565
|
+
session::SessionEvent::Frame {
|
|
566
|
+
seq,
|
|
567
|
+
damage,
|
|
568
|
+
timestamp_us,
|
|
569
|
+
} => (
|
|
458
570
|
"session.frame.changed",
|
|
459
|
-
serde_json::json!({ "sessionId": session_id, "seq": seq, "damage": damage }),
|
|
571
|
+
serde_json::json!({ "sessionId": session_id, "seq": seq, "damage": damage, "timestamp_us": timestamp_us }),
|
|
460
572
|
),
|
|
461
573
|
session::SessionEvent::Input { input } => (
|
|
462
574
|
"session.input",
|
|
@@ -474,9 +586,9 @@ fn render_event(notice: session::Notice) -> Option<String> {
|
|
|
474
586
|
"session.capture.stopped",
|
|
475
587
|
serde_json::json!({ "sessionId": session_id, "reason": reason }),
|
|
476
588
|
),
|
|
477
|
-
session::SessionEvent::Revoked { reason } => (
|
|
589
|
+
session::SessionEvent::Revoked { reason, code } => (
|
|
478
590
|
"session.revoked",
|
|
479
|
-
serde_json::json!({ "sessionId": session_id, "reason": reason }),
|
|
591
|
+
serde_json::json!({ "sessionId": session_id, "reason": reason, "code": code }),
|
|
480
592
|
),
|
|
481
593
|
};
|
|
482
594
|
serde_json::to_string(&Event {
|
|
@@ -486,7 +598,10 @@ fn render_event(notice: session::Notice) -> Option<String> {
|
|
|
486
598
|
.ok()
|
|
487
599
|
}
|
|
488
600
|
|
|
489
|
-
#[cfg(any(
|
|
601
|
+
#[cfg(any(
|
|
602
|
+
target_os = "linux",
|
|
603
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
604
|
+
))]
|
|
490
605
|
async fn dispatch(
|
|
491
606
|
request: &Request,
|
|
492
607
|
hello_seen: &mut bool,
|
|
@@ -529,6 +644,7 @@ async fn dispatch(
|
|
|
529
644
|
.map_err(|error| ErrorBody::new("malformed", error.to_string()))?;
|
|
530
645
|
let open = session::OpenRequest {
|
|
531
646
|
source: params.source,
|
|
647
|
+
cursor: params.cursor,
|
|
532
648
|
permissions: params.permissions,
|
|
533
649
|
max_width: params.max_width,
|
|
534
650
|
max_height: params.max_height,
|
|
@@ -538,6 +654,7 @@ async fn dispatch(
|
|
|
538
654
|
ttl: params.ttl_seconds.map(Duration::from_secs),
|
|
539
655
|
loopback_tcp: params.loopback_tcp,
|
|
540
656
|
agent_indicator: params.agent_indicator,
|
|
657
|
+
local_frames: params.local_frames,
|
|
541
658
|
ice_servers: params
|
|
542
659
|
.ice_servers
|
|
543
660
|
.into_iter()
|
|
@@ -562,10 +679,21 @@ async fn dispatch(
|
|
|
562
679
|
"origin": { "x": session.source().origin_x, "y": session.source().origin_y },
|
|
563
680
|
},
|
|
564
681
|
"geometry": session.geometry(),
|
|
682
|
+
"cursor": session.cursor_info(),
|
|
565
683
|
});
|
|
566
684
|
*current = Some(session);
|
|
567
685
|
Ok(result)
|
|
568
686
|
}
|
|
687
|
+
"session.point" => {
|
|
688
|
+
let session = require_session(current)?;
|
|
689
|
+
let params: protocol::PointParams = serde_json::from_value(request.params.clone())
|
|
690
|
+
.map_err(|error| ErrorBody::new("malformed", error.to_string()))?;
|
|
691
|
+
check_session(session, ¶ms.session_id, None)?;
|
|
692
|
+
session
|
|
693
|
+
.point(¶ms)
|
|
694
|
+
.map_err(|error| ErrorBody::new(error.code, error.message))?;
|
|
695
|
+
Ok(serde_json::json!({"shown": !params.clear}))
|
|
696
|
+
}
|
|
569
697
|
"session.description" => {
|
|
570
698
|
let session = require_session(current)?;
|
|
571
699
|
let params: protocol::DescriptionParams =
|
|
@@ -687,7 +815,10 @@ async fn dispatch(
|
|
|
687
815
|
}
|
|
688
816
|
}
|
|
689
817
|
|
|
690
|
-
#[cfg(any(
|
|
818
|
+
#[cfg(any(
|
|
819
|
+
target_os = "linux",
|
|
820
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
821
|
+
))]
|
|
691
822
|
fn require_session(
|
|
692
823
|
current: &mut Option<session::Session>,
|
|
693
824
|
) -> std::result::Result<&mut session::Session, ErrorBody> {
|
|
@@ -698,7 +829,10 @@ fn require_session(
|
|
|
698
829
|
|
|
699
830
|
/// A late message for a session that has already ended must not revive it, and a
|
|
700
831
|
/// message for a different session must not reach this one.
|
|
701
|
-
#[cfg(any(
|
|
832
|
+
#[cfg(any(
|
|
833
|
+
target_os = "linux",
|
|
834
|
+
all(any(target_os = "macos", target_os = "windows"), desklink_vpx)
|
|
835
|
+
))]
|
|
702
836
|
fn check_session(
|
|
703
837
|
session: &session::Session,
|
|
704
838
|
id: &str,
|
|
@@ -723,6 +857,11 @@ fn main() {
|
|
|
723
857
|
std::process::exit(mac::run());
|
|
724
858
|
}
|
|
725
859
|
|
|
860
|
+
#[cfg(target_os = "windows")]
|
|
861
|
+
fn main() {
|
|
862
|
+
std::process::exit(win::run());
|
|
863
|
+
}
|
|
864
|
+
|
|
726
865
|
#[cfg(all(test, target_os = "linux"))]
|
|
727
866
|
mod tests {
|
|
728
867
|
use super::*;
|
|
@@ -744,6 +883,27 @@ mod tests {
|
|
|
744
883
|
assert!(!hello_seen, "a refused handshake must not open the gate");
|
|
745
884
|
}
|
|
746
885
|
|
|
886
|
+
#[test]
|
|
887
|
+
fn cursor_notice_preserves_source_coordinates_visibility_and_clock() {
|
|
888
|
+
let line = render_event(session::Notice {
|
|
889
|
+
session_id: String::from("cursor-session"),
|
|
890
|
+
event: session::SessionEvent::Cursor {
|
|
891
|
+
position: protocol::CursorPosition {
|
|
892
|
+
x: 32,
|
|
893
|
+
y: 64,
|
|
894
|
+
visible: false,
|
|
895
|
+
timestamp_us: 123456,
|
|
896
|
+
},
|
|
897
|
+
},
|
|
898
|
+
})
|
|
899
|
+
.unwrap();
|
|
900
|
+
let parsed: serde_json::Value = serde_json::from_str(&line).unwrap();
|
|
901
|
+
assert_eq!(
|
|
902
|
+
parsed,
|
|
903
|
+
serde_json::json!({"event":"session.cursor","params":{"sessionId":"cursor-session","x":32,"y":64,"visible":false,"timestamp_us":123456}})
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
|
|
747
907
|
#[tokio::test]
|
|
748
908
|
async fn the_state_notification_carries_exactly_what_the_document_promises() {
|
|
749
909
|
let line = render_event(session::Notice {
|