@desklink/host 0.1.0 → 0.2.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.
- package/NOTICE +3 -0
- package/README.md +72 -16
- package/bin/desklink-host.mjs +14 -3
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +5 -1
- package/dist/bridge.js.map +1 -1
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +17 -5
- package/dist/engineProcess.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/keeper.d.ts +52 -0
- package/dist/keeper.d.ts.map +1 -0
- package/dist/keeper.js +101 -0
- package/dist/keeper.js.map +1 -0
- package/dist/protocol.d.ts +42 -5
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/resolveEngine.d.ts +3 -2
- package/dist/resolveEngine.d.ts.map +1 -1
- package/dist/resolveEngine.js +20 -5
- package/dist/resolveEngine.js.map +1 -1
- package/docs/BOUNDARY.md +11 -6
- package/docs/PROTOCOL.md +297 -33
- package/engine/Cargo.lock +196 -1
- package/engine/Cargo.toml +26 -5
- package/engine/build.rs +98 -23
- package/engine/native/agent_overlay_mac.m +133 -0
- package/engine/native/agent_overlay_wayland.c +192 -0
- package/engine/native/agent_overlay_x11.c +103 -0
- package/engine/native/mac_stream.mm +188 -0
- package/engine/src/capture.rs +169 -19
- package/engine/src/capture_mac.rs +145 -0
- package/engine/src/clipboard_mac.rs +182 -0
- package/engine/src/convert.rs +57 -1
- package/engine/src/indicator.rs +162 -0
- package/engine/src/input.rs +12 -0
- package/engine/src/input_mac.rs +312 -0
- package/engine/src/keeper.rs +622 -0
- package/engine/src/keymap.rs +25 -0
- package/engine/src/keymap_mac.rs +209 -0
- package/engine/src/mac.rs +722 -0
- package/engine/src/main.rs +158 -2
- package/engine/src/peer.rs +429 -22
- package/engine/src/portal.rs +4 -0
- package/engine/src/portal_mac.rs +68 -0
- package/engine/src/protocol.rs +186 -3
- package/engine/src/session.rs +1307 -100
- package/engine/src/x11.rs +23 -3
- package/engine/src/x11_mac.rs +40 -0
- package/examples/reference-client.html +33 -4
- package/package.json +2 -2
package/engine/Cargo.lock
CHANGED
|
@@ -257,6 +257,15 @@ dependencies = [
|
|
|
257
257
|
"generic-array",
|
|
258
258
|
]
|
|
259
259
|
|
|
260
|
+
[[package]]
|
|
261
|
+
name = "block2"
|
|
262
|
+
version = "0.6.2"
|
|
263
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
264
|
+
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
|
265
|
+
dependencies = [
|
|
266
|
+
"objc2",
|
|
267
|
+
]
|
|
268
|
+
|
|
260
269
|
[[package]]
|
|
261
270
|
name = "bumpalo"
|
|
262
271
|
version = "3.20.3"
|
|
@@ -508,16 +517,23 @@ checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
|
508
517
|
|
|
509
518
|
[[package]]
|
|
510
519
|
name = "desklink-host"
|
|
511
|
-
version = "0.
|
|
520
|
+
version = "0.2.0"
|
|
512
521
|
dependencies = [
|
|
513
522
|
"anyhow",
|
|
514
523
|
"ashpd",
|
|
515
524
|
"async-trait",
|
|
525
|
+
"base64 0.22.1",
|
|
526
|
+
"block2",
|
|
516
527
|
"bytes",
|
|
517
528
|
"cc",
|
|
518
529
|
"futures-util",
|
|
519
530
|
"libc",
|
|
520
531
|
"log",
|
|
532
|
+
"objc2-core-foundation",
|
|
533
|
+
"objc2-core-graphics",
|
|
534
|
+
"objc2-core-media",
|
|
535
|
+
"objc2-foundation",
|
|
536
|
+
"objc2-screen-capture-kit",
|
|
521
537
|
"pipewire",
|
|
522
538
|
"rand 0.8.8",
|
|
523
539
|
"rtc",
|
|
@@ -541,6 +557,16 @@ dependencies = [
|
|
|
541
557
|
"subtle",
|
|
542
558
|
]
|
|
543
559
|
|
|
560
|
+
[[package]]
|
|
561
|
+
name = "dispatch2"
|
|
562
|
+
version = "0.3.1"
|
|
563
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
564
|
+
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
|
565
|
+
dependencies = [
|
|
566
|
+
"bitflags 2.13.2",
|
|
567
|
+
"objc2",
|
|
568
|
+
]
|
|
569
|
+
|
|
544
570
|
[[package]]
|
|
545
571
|
name = "displaydoc"
|
|
546
572
|
version = "0.2.7"
|
|
@@ -1211,6 +1237,175 @@ dependencies = [
|
|
|
1211
1237
|
"autocfg",
|
|
1212
1238
|
]
|
|
1213
1239
|
|
|
1240
|
+
[[package]]
|
|
1241
|
+
name = "objc2"
|
|
1242
|
+
version = "0.6.4"
|
|
1243
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1244
|
+
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
|
1245
|
+
dependencies = [
|
|
1246
|
+
"objc2-encode",
|
|
1247
|
+
]
|
|
1248
|
+
|
|
1249
|
+
[[package]]
|
|
1250
|
+
name = "objc2-av-foundation"
|
|
1251
|
+
version = "0.3.2"
|
|
1252
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1253
|
+
checksum = "478ae33fcac9df0a18db8302387c666b8ef08a3e2d62b510ca4fc278a384b6c0"
|
|
1254
|
+
dependencies = [
|
|
1255
|
+
"objc2",
|
|
1256
|
+
"objc2-foundation",
|
|
1257
|
+
]
|
|
1258
|
+
|
|
1259
|
+
[[package]]
|
|
1260
|
+
name = "objc2-core-audio"
|
|
1261
|
+
version = "0.3.2"
|
|
1262
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1263
|
+
checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2"
|
|
1264
|
+
dependencies = [
|
|
1265
|
+
"dispatch2",
|
|
1266
|
+
"objc2",
|
|
1267
|
+
"objc2-core-audio-types",
|
|
1268
|
+
"objc2-core-foundation",
|
|
1269
|
+
]
|
|
1270
|
+
|
|
1271
|
+
[[package]]
|
|
1272
|
+
name = "objc2-core-audio-types"
|
|
1273
|
+
version = "0.3.2"
|
|
1274
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1275
|
+
checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c"
|
|
1276
|
+
dependencies = [
|
|
1277
|
+
"bitflags 2.13.2",
|
|
1278
|
+
"objc2",
|
|
1279
|
+
]
|
|
1280
|
+
|
|
1281
|
+
[[package]]
|
|
1282
|
+
name = "objc2-core-foundation"
|
|
1283
|
+
version = "0.3.2"
|
|
1284
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1285
|
+
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
|
1286
|
+
dependencies = [
|
|
1287
|
+
"bitflags 2.13.2",
|
|
1288
|
+
"block2",
|
|
1289
|
+
"dispatch2",
|
|
1290
|
+
"libc",
|
|
1291
|
+
"objc2",
|
|
1292
|
+
]
|
|
1293
|
+
|
|
1294
|
+
[[package]]
|
|
1295
|
+
name = "objc2-core-graphics"
|
|
1296
|
+
version = "0.3.2"
|
|
1297
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1298
|
+
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
|
|
1299
|
+
dependencies = [
|
|
1300
|
+
"bitflags 2.13.2",
|
|
1301
|
+
"block2",
|
|
1302
|
+
"dispatch2",
|
|
1303
|
+
"libc",
|
|
1304
|
+
"objc2",
|
|
1305
|
+
"objc2-core-foundation",
|
|
1306
|
+
"objc2-io-surface",
|
|
1307
|
+
"objc2-metal",
|
|
1308
|
+
]
|
|
1309
|
+
|
|
1310
|
+
[[package]]
|
|
1311
|
+
name = "objc2-core-media"
|
|
1312
|
+
version = "0.3.2"
|
|
1313
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1314
|
+
checksum = "05ec576860167a15dd9fce7fbee7512beb4e31f532159d3482d1f9c6caedf31d"
|
|
1315
|
+
dependencies = [
|
|
1316
|
+
"bitflags 2.13.2",
|
|
1317
|
+
"block2",
|
|
1318
|
+
"dispatch2",
|
|
1319
|
+
"objc2",
|
|
1320
|
+
"objc2-core-audio",
|
|
1321
|
+
"objc2-core-audio-types",
|
|
1322
|
+
"objc2-core-foundation",
|
|
1323
|
+
"objc2-core-video",
|
|
1324
|
+
]
|
|
1325
|
+
|
|
1326
|
+
[[package]]
|
|
1327
|
+
name = "objc2-core-video"
|
|
1328
|
+
version = "0.3.2"
|
|
1329
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1330
|
+
checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6"
|
|
1331
|
+
dependencies = [
|
|
1332
|
+
"bitflags 2.13.2",
|
|
1333
|
+
"objc2",
|
|
1334
|
+
"objc2-core-foundation",
|
|
1335
|
+
"objc2-core-graphics",
|
|
1336
|
+
"objc2-io-surface",
|
|
1337
|
+
]
|
|
1338
|
+
|
|
1339
|
+
[[package]]
|
|
1340
|
+
name = "objc2-encode"
|
|
1341
|
+
version = "4.1.0"
|
|
1342
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1343
|
+
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
|
1344
|
+
|
|
1345
|
+
[[package]]
|
|
1346
|
+
name = "objc2-foundation"
|
|
1347
|
+
version = "0.3.2"
|
|
1348
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1349
|
+
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
|
1350
|
+
dependencies = [
|
|
1351
|
+
"bitflags 2.13.2",
|
|
1352
|
+
"block2",
|
|
1353
|
+
"libc",
|
|
1354
|
+
"objc2",
|
|
1355
|
+
"objc2-core-foundation",
|
|
1356
|
+
]
|
|
1357
|
+
|
|
1358
|
+
[[package]]
|
|
1359
|
+
name = "objc2-io-surface"
|
|
1360
|
+
version = "0.3.2"
|
|
1361
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1362
|
+
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
|
|
1363
|
+
dependencies = [
|
|
1364
|
+
"bitflags 2.13.2",
|
|
1365
|
+
"objc2",
|
|
1366
|
+
"objc2-core-foundation",
|
|
1367
|
+
]
|
|
1368
|
+
|
|
1369
|
+
[[package]]
|
|
1370
|
+
name = "objc2-metal"
|
|
1371
|
+
version = "0.3.2"
|
|
1372
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1373
|
+
checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
|
|
1374
|
+
dependencies = [
|
|
1375
|
+
"bitflags 2.13.2",
|
|
1376
|
+
"objc2",
|
|
1377
|
+
"objc2-foundation",
|
|
1378
|
+
]
|
|
1379
|
+
|
|
1380
|
+
[[package]]
|
|
1381
|
+
name = "objc2-screen-capture-kit"
|
|
1382
|
+
version = "0.3.2"
|
|
1383
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1384
|
+
checksum = "74b7c5390f477482f001bc354d6571a70db7e4f8d5288e860c45521fbce11394"
|
|
1385
|
+
dependencies = [
|
|
1386
|
+
"bitflags 2.13.2",
|
|
1387
|
+
"block2",
|
|
1388
|
+
"dispatch2",
|
|
1389
|
+
"libc",
|
|
1390
|
+
"objc2",
|
|
1391
|
+
"objc2-av-foundation",
|
|
1392
|
+
"objc2-core-foundation",
|
|
1393
|
+
"objc2-core-graphics",
|
|
1394
|
+
"objc2-core-media",
|
|
1395
|
+
"objc2-foundation",
|
|
1396
|
+
"objc2-uniform-type-identifiers",
|
|
1397
|
+
]
|
|
1398
|
+
|
|
1399
|
+
[[package]]
|
|
1400
|
+
name = "objc2-uniform-type-identifiers"
|
|
1401
|
+
version = "0.3.2"
|
|
1402
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1403
|
+
checksum = "7902ac02859fc1f7045f8b598c63f1ae0cc7efeaa06a9bc9f3d9a3c955974fa4"
|
|
1404
|
+
dependencies = [
|
|
1405
|
+
"objc2",
|
|
1406
|
+
"objc2-foundation",
|
|
1407
|
+
]
|
|
1408
|
+
|
|
1214
1409
|
[[package]]
|
|
1215
1410
|
name = "oid-registry"
|
|
1216
1411
|
version = "0.7.1"
|
package/engine/Cargo.toml
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "desklink-host"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
edition = "2021"
|
|
5
|
+
rust-version = "1.97.1"
|
|
5
6
|
license = "Apache-2.0"
|
|
6
7
|
description = "Per-user on-demand desktop capture, encode and input engine speaking a versioned local control protocol"
|
|
7
8
|
publish = false
|
|
@@ -11,23 +12,43 @@ name = "desklink-host"
|
|
|
11
12
|
path = "src/main.rs"
|
|
12
13
|
|
|
13
14
|
[dependencies]
|
|
14
|
-
anyhow = "1"
|
|
15
15
|
serde = { version = "1", features = ["derive"] }
|
|
16
16
|
serde_json = "1"
|
|
17
|
+
base64 = "0.22"
|
|
18
|
+
|
|
19
|
+
[target.'cfg(target_os = "linux")'.dependencies]
|
|
20
|
+
anyhow = "1"
|
|
17
21
|
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal"] }
|
|
18
22
|
futures-util = "0.3"
|
|
19
|
-
ashpd = { version = "0.11", default-features = false, features = ["tokio"] }
|
|
20
|
-
pipewire = { version = "0.10", features = ["v0_3_44"] }
|
|
21
23
|
libc = "0.2"
|
|
22
24
|
bytes = "1"
|
|
23
25
|
webrtc = { version = "0.21", default-features = false, features = ["runtime-tokio", "crypto-ring"] }
|
|
24
26
|
rtc = { version = "0.21", default-features = false, features = ["crypto-ring"] }
|
|
27
|
+
log = "0.4"
|
|
28
|
+
async-trait = "0.1"
|
|
29
|
+
rand = "0.8"
|
|
30
|
+
ashpd = { version = "0.11", default-features = false, features = ["tokio"] }
|
|
31
|
+
pipewire = { version = "0.10", features = ["v0_3_44"] }
|
|
25
32
|
xkbcommon = "0.8"
|
|
26
33
|
x11rb = { version = "0.14", default-features = false, features = ["allow-unsafe-code", "xtest"] }
|
|
27
34
|
wl-clipboard-rs = "0.9"
|
|
28
|
-
|
|
35
|
+
|
|
36
|
+
[target.'cfg(target_os = "macos")'.dependencies]
|
|
37
|
+
anyhow = "1"
|
|
29
38
|
async-trait = "0.1"
|
|
39
|
+
bytes = "1"
|
|
40
|
+
libc = "0.2"
|
|
41
|
+
log = "0.4"
|
|
30
42
|
rand = "0.8"
|
|
43
|
+
rtc = { version = "0.21", default-features = false, features = ["crypto-ring"] }
|
|
44
|
+
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal"] }
|
|
45
|
+
webrtc = { version = "0.21", default-features = false, features = ["runtime-tokio", "crypto-ring"] }
|
|
46
|
+
objc2-screen-capture-kit = { version = "0.3.2", features = ["SCStream", "SCShareableContent", "SCError", "SCScreenshotManager", "block2", "dispatch2", "objc2-core-media", "objc2-core-graphics"] }
|
|
47
|
+
objc2-foundation = { version = "0.3.2", features = ["NSArray", "NSError", "NSString"] }
|
|
48
|
+
objc2-core-media = "0.3.2"
|
|
49
|
+
objc2-core-foundation = "0.3.2"
|
|
50
|
+
objc2-core-graphics = { version = "0.3.2", features = ["CGImage", "CGDataProvider"] }
|
|
51
|
+
block2 = "0.6"
|
|
31
52
|
|
|
32
53
|
[build-dependencies]
|
|
33
54
|
cc = "1"
|
package/engine/build.rs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
//! Native dependencies of the engine.
|
|
2
2
|
//!
|
|
3
|
-
//!
|
|
4
|
-
//! sources — no prebuilt binary is fetched, and nothing is
|
|
3
|
+
//! The Linux build uses two permissive C libraries, both built or linked from
|
|
4
|
+
//! this machine's own sources — no prebuilt binary is fetched, and nothing is
|
|
5
|
+
//! installed:
|
|
5
6
|
//!
|
|
6
7
|
//! * libvpx (BSD-3-Clause) — VP9 encode, through `native/vpx_shim.c` so the
|
|
7
8
|
//! versioned encoder config struct is laid out by a C compiler.
|
|
@@ -9,9 +10,9 @@
|
|
|
9
10
|
//! over `uinput`/`libevdev`, built by its own CMake project into a static
|
|
10
11
|
//! library and called through its documented C API.
|
|
11
12
|
//!
|
|
12
|
-
//!
|
|
13
|
-
//!
|
|
14
|
-
//!
|
|
13
|
+
//! macOS builds only the libvpx shim; ScreenCaptureKit, Quartz input and
|
|
14
|
+
//! AppKit clipboard use native frameworks. Linux runtime input access is still
|
|
15
|
+
//! checked through `/dev/uinput`.
|
|
15
16
|
//!
|
|
16
17
|
//! `DESKLINK_VPX_STATIC_DIR` names a libvpx install prefix (`include/`, `lib/`)
|
|
17
18
|
//! to link statically instead. The prebuilt engine uses it, because libvpx's
|
|
@@ -21,40 +22,114 @@
|
|
|
21
22
|
use std::path::{Path, PathBuf};
|
|
22
23
|
|
|
23
24
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
25
|
+
println!("cargo:rustc-check-cfg=cfg(desklink_vpx)");
|
|
26
|
+
println!("cargo:rustc-check-cfg=cfg(desklink_macos_cli)");
|
|
24
27
|
println!("cargo:rerun-if-changed=native/vpx_shim.c");
|
|
25
28
|
println!("cargo:rerun-if-changed=native/inputtino_shim.cpp");
|
|
29
|
+
println!("cargo:rerun-if-changed=native/mac_stream.mm");
|
|
30
|
+
println!("cargo:rerun-if-changed=native/agent_overlay_mac.m");
|
|
31
|
+
println!("cargo:rerun-if-changed=native/agent_overlay_x11.c");
|
|
32
|
+
println!("cargo:rerun-if-changed=native/agent_overlay_wayland.c");
|
|
33
|
+
println!("cargo:rerun-if-changed=Info.plist");
|
|
26
34
|
println!("cargo:rerun-if-changed=vendor/inputtino/src/uinput/include/inputtino/keyboard.hpp");
|
|
27
35
|
println!("cargo:rerun-if-changed=vendor/inputtino/include/inputtino/input.h");
|
|
28
36
|
println!("cargo:rerun-if-changed=vendor/inputtino/CMakeLists.txt");
|
|
29
37
|
|
|
30
38
|
println!("cargo:rerun-if-env-changed=DESKLINK_VPX_STATIC_DIR");
|
|
39
|
+
println!("cargo:rerun-if-env-changed=DESKLINK_MACOS_CLI");
|
|
31
40
|
|
|
32
|
-
let
|
|
33
|
-
let
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
|
42
|
+
if let Some(prefix) = std::env::var_os("DESKLINK_VPX_STATIC_DIR").map(PathBuf::from) {
|
|
43
|
+
if !prefix.join("include/vpx/vp8cx.h").exists() || !prefix.join("lib/libvpx.a").exists() {
|
|
44
|
+
return Err(format!("DESKLINK_VPX_STATIC_DIR must be the libvpx install prefix containing include/vpx/vp8cx.h and lib/libvpx.a, not its lib directory: {}", prefix.display()).into());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if target_os == "macos" && std::env::var_os("DESKLINK_MACOS_CLI").is_some() {
|
|
48
|
+
println!("cargo:rustc-cfg=desklink_macos_cli");
|
|
49
|
+
}
|
|
50
|
+
if target_os == "linux" {
|
|
51
|
+
let static_vpx = std::env::var_os("DESKLINK_VPX_STATIC_DIR").map(PathBuf::from);
|
|
52
|
+
let mut shim = cc::Build::new();
|
|
53
|
+
shim.file("native/vpx_shim.c")
|
|
54
|
+
.flag_if_supported("-Wno-unused-parameter");
|
|
55
|
+
if let Some(prefix) = &static_vpx {
|
|
56
|
+
shim.include(prefix.join("include"));
|
|
57
|
+
}
|
|
58
|
+
shim.compile("dlvpx");
|
|
59
|
+
match &static_vpx {
|
|
60
|
+
Some(prefix) => {
|
|
61
|
+
println!(
|
|
62
|
+
"cargo:rustc-link-search=native={}",
|
|
63
|
+
prefix.join("lib").display()
|
|
64
|
+
);
|
|
65
|
+
println!("cargo:rustc-link-lib=static=vpx");
|
|
66
|
+
}
|
|
67
|
+
None => println!("cargo:rustc-link-lib=vpx"),
|
|
68
|
+
}
|
|
38
69
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
70
|
+
|
|
71
|
+
if target_os == "linux" {
|
|
72
|
+
cc::Build::new()
|
|
73
|
+
.file("native/agent_overlay_x11.c")
|
|
74
|
+
.file("native/agent_overlay_wayland.c")
|
|
75
|
+
.compile("dlagentoverlay");
|
|
76
|
+
for lib in ["X11", "Xcursor", "wayland-client", "m"] {
|
|
77
|
+
println!("cargo:rustc-link-lib={lib}");
|
|
78
|
+
}
|
|
79
|
+
cc::Build::new()
|
|
80
|
+
.cpp(true)
|
|
81
|
+
.std("c++17")
|
|
82
|
+
.include("vendor/inputtino/src/uinput/include")
|
|
83
|
+
.file("native/inputtino_shim.cpp")
|
|
84
|
+
.compile("dlinputkey");
|
|
85
|
+
build_inputtino(&PathBuf::from(std::env::var("OUT_DIR")?))?;
|
|
86
|
+
} else if target_os == "macos" {
|
|
87
|
+
cc::Build::new()
|
|
88
|
+
.cpp(true)
|
|
89
|
+
.file("native/mac_stream.mm")
|
|
90
|
+
.flag("-fobjc-arc")
|
|
91
|
+
.compile("dlmacstream");
|
|
92
|
+
cc::Build::new()
|
|
93
|
+
.file("native/agent_overlay_mac.m")
|
|
94
|
+
.flag("-fobjc-arc")
|
|
95
|
+
.compile("dlagentoverlay");
|
|
96
|
+
for framework in [
|
|
97
|
+
"ScreenCaptureKit",
|
|
98
|
+
"CoreVideo",
|
|
99
|
+
"CoreMedia",
|
|
100
|
+
"Foundation",
|
|
101
|
+
"AppKit",
|
|
102
|
+
"QuartzCore",
|
|
103
|
+
] {
|
|
104
|
+
println!("cargo:rustc-link-lib=framework={framework}");
|
|
105
|
+
}
|
|
106
|
+
if let Some(prefix) = std::env::var_os("DESKLINK_VPX_STATIC_DIR").map(PathBuf::from) {
|
|
107
|
+
cc::Build::new()
|
|
108
|
+
.file("native/vpx_shim.c")
|
|
109
|
+
.include(prefix.join("include"))
|
|
110
|
+
.compile("dlvpx");
|
|
42
111
|
println!(
|
|
43
112
|
"cargo:rustc-link-search=native={}",
|
|
44
113
|
prefix.join("lib").display()
|
|
45
114
|
);
|
|
46
115
|
println!("cargo:rustc-link-lib=static=vpx");
|
|
116
|
+
println!("cargo:rustc-cfg=desklink_vpx");
|
|
117
|
+
}
|
|
118
|
+
println!("cargo:rustc-link-lib=framework=CoreGraphics");
|
|
119
|
+
println!("cargo:rustc-link-lib=framework=ApplicationServices");
|
|
120
|
+
println!("cargo:rustc-link-lib=framework=Carbon");
|
|
121
|
+
// The dev harness embeds its bundle identity for local TCC qualification.
|
|
122
|
+
// The published CLI must inherit the responsible app's TCC identity instead.
|
|
123
|
+
if std::env::var_os("DESKLINK_MACOS_CLI").is_none() {
|
|
124
|
+
println!("cargo:rustc-link-arg-bins=-sectcreate");
|
|
125
|
+
println!("cargo:rustc-link-arg-bins=__TEXT");
|
|
126
|
+
println!("cargo:rustc-link-arg-bins=__info_plist");
|
|
127
|
+
println!(
|
|
128
|
+
"cargo:rustc-link-arg-bins={}",
|
|
129
|
+
Path::new("Info.plist").canonicalize()?.display()
|
|
130
|
+
);
|
|
47
131
|
}
|
|
48
|
-
None => println!("cargo:rustc-link-lib=vpx"),
|
|
49
132
|
}
|
|
50
|
-
|
|
51
|
-
cc::Build::new()
|
|
52
|
-
.cpp(true)
|
|
53
|
-
.std("c++17")
|
|
54
|
-
.include("vendor/inputtino/src/uinput/include")
|
|
55
|
-
.file("native/inputtino_shim.cpp")
|
|
56
|
-
.compile("dlinputkey");
|
|
57
|
-
build_inputtino(&PathBuf::from(std::env::var("OUT_DIR")?))?;
|
|
58
133
|
Ok(())
|
|
59
134
|
}
|
|
60
135
|
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#import <AppKit/AppKit.h>
|
|
2
|
+
#import <QuartzCore/QuartzCore.h>
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
#include <unistd.h>
|
|
6
|
+
|
|
7
|
+
@interface AgentOverlayView : NSView {
|
|
8
|
+
NSPoint target, cursor;
|
|
9
|
+
CFTimeInterval clickAt, typeAt, endingAt;
|
|
10
|
+
BOOL positioned;
|
|
11
|
+
}
|
|
12
|
+
- (void)event:(char)kind x:(double)x y:(double)y;
|
|
13
|
+
- (void)end;
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
@implementation AgentOverlayView
|
|
17
|
+
- (BOOL)isOpaque { return NO; }
|
|
18
|
+
- (void)event:(char)kind x:(double)x y:(double)y {
|
|
19
|
+
if (kind == 'S') { [self end]; return; }
|
|
20
|
+
if (x >= 0 && y >= 0) {
|
|
21
|
+
NSPoint point = NSMakePoint(x, self.bounds.size.height - y);
|
|
22
|
+
target = point;
|
|
23
|
+
if (!positioned) { cursor = point; positioned = YES; }
|
|
24
|
+
}
|
|
25
|
+
CFTimeInterval now = CACurrentMediaTime();
|
|
26
|
+
if (kind == 'C') clickAt = now;
|
|
27
|
+
if (kind == 'T') typeAt = now;
|
|
28
|
+
[self setNeedsDisplay:YES];
|
|
29
|
+
}
|
|
30
|
+
- (void)end { endingAt = CACurrentMediaTime(); }
|
|
31
|
+
- (void)tick {
|
|
32
|
+
if (endingAt && CACurrentMediaTime() - endingAt > 0.7) { [NSApp terminate:nil]; return; }
|
|
33
|
+
cursor.x += (target.x - cursor.x) * 0.24;
|
|
34
|
+
cursor.y += (target.y - cursor.y) * 0.24;
|
|
35
|
+
[self setNeedsDisplay:YES];
|
|
36
|
+
}
|
|
37
|
+
- (void)drawRect:(NSRect)rect {
|
|
38
|
+
[[NSColor clearColor] set]; NSRectFillUsingOperation(rect, NSCompositingOperationCopy);
|
|
39
|
+
CFTimeInterval now = CACurrentMediaTime();
|
|
40
|
+
CGFloat edge = endingAt ? fmax(0, 1 - (now-endingAt)/0.7) : 1;
|
|
41
|
+
if (edge > 0) {
|
|
42
|
+
NSRect bounds = self.bounds;
|
|
43
|
+
[[NSColor colorWithCalibratedRed:0.28 green:0.67 blue:0.96 alpha:0.75*edge] set];
|
|
44
|
+
NSBezierPath *border = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(bounds, 4, 4) xRadius:12 yRadius:12];
|
|
45
|
+
border.lineWidth = 5; [border stroke];
|
|
46
|
+
}
|
|
47
|
+
if (!positioned) return;
|
|
48
|
+
NSBezierPath *pointer = [NSBezierPath bezierPath];
|
|
49
|
+
[pointer moveToPoint:NSMakePoint(cursor.x, cursor.y)];
|
|
50
|
+
[pointer lineToPoint:NSMakePoint(cursor.x+2, cursor.y-24)];
|
|
51
|
+
[pointer lineToPoint:NSMakePoint(cursor.x+8, cursor.y-18)];
|
|
52
|
+
[pointer lineToPoint:NSMakePoint(cursor.x+15, cursor.y-31)];
|
|
53
|
+
[pointer lineToPoint:NSMakePoint(cursor.x+21, cursor.y-28)];
|
|
54
|
+
[pointer lineToPoint:NSMakePoint(cursor.x+14, cursor.y-15)];
|
|
55
|
+
[pointer lineToPoint:NSMakePoint(cursor.x+24, cursor.y-14)];
|
|
56
|
+
[pointer closePath];
|
|
57
|
+
[[NSColor colorWithCalibratedRed:0.16 green:0.60 blue:1 alpha:1] set]; [pointer fill];
|
|
58
|
+
[[NSColor whiteColor] set]; pointer.lineWidth = 2; [pointer stroke];
|
|
59
|
+
for (int i = 3; i >= 0; i--) {
|
|
60
|
+
CGFloat radius = 12 + i*5;
|
|
61
|
+
CGFloat alpha = 0.13 * (1.0 - i/5.0);
|
|
62
|
+
[[NSColor colorWithCalibratedRed:0.30 green:0.73 blue:1 alpha:alpha] set];
|
|
63
|
+
NSBezierPath *halo = [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(cursor.x-radius, cursor.y-radius, radius*2, radius*2)];
|
|
64
|
+
halo.lineWidth = 1.5 + i; [halo stroke];
|
|
65
|
+
}
|
|
66
|
+
if (clickAt && now-clickAt < 0.55) {
|
|
67
|
+
CGFloat progress = (now-clickAt)/0.55;
|
|
68
|
+
CGFloat radius = 11 + 37*progress;
|
|
69
|
+
[[NSColor colorWithCalibratedRed:0.37 green:0.77 blue:1 alpha:0.45*(1-progress)] set];
|
|
70
|
+
NSBezierPath *ripple = [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(target.x-radius,target.y-radius,2*radius,2*radius)];
|
|
71
|
+
ripple.lineWidth = 2.5*(1-progress)+0.5; [ripple stroke];
|
|
72
|
+
}
|
|
73
|
+
if (typeAt && now-typeAt < 0.4) {
|
|
74
|
+
CGFloat progress = (now-typeAt)/0.4;
|
|
75
|
+
CGFloat radius = 5 + progress*15;
|
|
76
|
+
[[NSColor colorWithCalibratedRed:0.50 green:0.83 blue:1 alpha:0.32*(1-progress)] set];
|
|
77
|
+
[[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(target.x-radius,target.y-radius,2*radius,2*radius)] fill];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
@end
|
|
81
|
+
|
|
82
|
+
// The dev recording path converts ScreenCaptureKit screenshots to packed BGRA.
|
|
83
|
+
unsigned char *desklink_image_bgra(CGImageRef image, size_t *length, size_t *stride) {
|
|
84
|
+
size_t width = CGImageGetWidth(image), height = CGImageGetHeight(image);
|
|
85
|
+
*stride = width * 4; *length = *stride * height;
|
|
86
|
+
unsigned char *pixels = malloc(*length);
|
|
87
|
+
if (!pixels) return NULL;
|
|
88
|
+
CGColorSpaceRef color = CGColorSpaceCreateDeviceRGB();
|
|
89
|
+
CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, *stride, color,
|
|
90
|
+
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
|
|
91
|
+
CGColorSpaceRelease(color);
|
|
92
|
+
if (!context) { free(pixels); return NULL; }
|
|
93
|
+
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
|
94
|
+
CGContextRelease(context);
|
|
95
|
+
return pixels;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
int desklink_agent_overlay_main(int display_id) {
|
|
99
|
+
@autoreleasepool {
|
|
100
|
+
[NSApplication sharedApplication];
|
|
101
|
+
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
|
|
102
|
+
NSScreen *screen = nil;
|
|
103
|
+
for (NSScreen *candidate in [NSScreen screens]) {
|
|
104
|
+
if ([candidate.deviceDescription[@"NSScreenNumber"] intValue] == display_id) { screen = candidate; break; }
|
|
105
|
+
}
|
|
106
|
+
if (!screen) return 2;
|
|
107
|
+
NSWindow *window = [[NSWindow alloc] initWithContentRect:screen.frame styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:NO screen:screen];
|
|
108
|
+
window.opaque = NO; window.backgroundColor = NSColor.clearColor;
|
|
109
|
+
window.ignoresMouseEvents = YES; window.hasShadow = NO;
|
|
110
|
+
window.level = NSScreenSaverWindowLevel - 1;
|
|
111
|
+
window.collectionBehavior = NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary;
|
|
112
|
+
AgentOverlayView *view = [[AgentOverlayView alloc] initWithFrame:NSMakeRect(0,0,screen.frame.size.width,screen.frame.size.height)];
|
|
113
|
+
window.contentView = view;
|
|
114
|
+
NSPoint mouse = [NSEvent mouseLocation];
|
|
115
|
+
[view event:'M' x:mouse.x-screen.frame.origin.x y:NSMaxY(screen.frame)-mouse.y];
|
|
116
|
+
[window orderFrontRegardless];
|
|
117
|
+
puts("READY"); fflush(stdout);
|
|
118
|
+
[NSTimer scheduledTimerWithTimeInterval:1.0/60 target:view selector:@selector(tick) userInfo:nil repeats:YES];
|
|
119
|
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
|
120
|
+
char line[128];
|
|
121
|
+
while (fgets(line, sizeof(line), stdin)) {
|
|
122
|
+
char kind; double x = 0, y = 0;
|
|
123
|
+
if (sscanf(line, "%c %lf %lf", &kind, &x, &y) >= 1) {
|
|
124
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [view event:kind x:x y:y]; });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [view end]; });
|
|
128
|
+
});
|
|
129
|
+
[NSApp run];
|
|
130
|
+
[window close];
|
|
131
|
+
}
|
|
132
|
+
return 0;
|
|
133
|
+
}
|