@desklink/host 0.3.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 +3 -0
- package/README.md +63 -15
- package/bin/desklink-host.mjs +12 -4
- package/dist/engineProcess.d.ts +6 -1
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +34 -4
- package/dist/engineProcess.js.map +1 -1
- package/dist/protocol.d.ts +32 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/resolveEngine.d.ts +6 -0
- package/dist/resolveEngine.d.ts.map +1 -1
- package/dist/resolveEngine.js +45 -6
- package/dist/resolveEngine.js.map +1 -1
- package/docs/PROTOCOL.md +119 -6
- package/engine/Cargo.lock +2 -2
- package/engine/Cargo.toml +7 -12
- package/engine/build.rs +61 -5
- 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/src/capture.rs +92 -3
- package/engine/src/capture_win.rs +23 -0
- package/engine/src/clipboard_win.rs +8 -0
- package/engine/src/cursor.rs +118 -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 +28 -6
- package/engine/src/main.rs +165 -23
- package/engine/src/portal.rs +42 -4
- package/engine/src/portal_win.rs +37 -0
- package/engine/src/protocol.rs +49 -0
- package/engine/src/session.rs +467 -17
- package/engine/src/win.rs +110 -0
- package/engine/src/x11.rs +15 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveEngine.js","sourceRoot":"","sources":["../src/resolveEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAsBzC,mDAAmD;AACnD,MAAM,kBAAkB,GAAG,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC;AAE7D,MAAM,UAAU,kBAAkB,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc;IAC7F,OAAO,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK,GAAG,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC7B,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACvB,WAAmB,OAAO,CAAC,QAAQ,EACnC,OAAe,OAAO,CAAC,IAAI,EAC3B,QAA6B,QAAQ,EAAE;IAEvC,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,SAAS,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IACrF,OAAO,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,yEAAyE;AACzE,SAAS,QAAQ;IACb,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAA+D,CAAC;IAC1G,OAAO,MAAM,EAAE,MAAM,EAAE,mBAAmB,KAAK,SAAS,CAAC;AAC7D,CAAC;AAED,SAAS,cAAc;IACnB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,kBAAkB,WAAW,EAAE,EAAE,CAAC;IAC/C,IAAI,CAAC;QACD,mEAAmE;QACnE,2DAA2D;QAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,IAAI,eAAe,CAA0D,CAAC;QAC1G,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACxE,IAAI,OAAO,QAAQ,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACjC,OAAO;QACH,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"resolveEngine.js","sourceRoot":"","sources":["../src/resolveEngine.ts"],"names":[],"mappings":"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"}
|
package/docs/PROTOCOL.md
CHANGED
|
@@ -5,10 +5,15 @@ the user's session starts it and talks to it over an inherited private channel
|
|
|
5
5
|
the engine never opens a public listener, never runs as root, and never installs
|
|
6
6
|
a service.
|
|
7
7
|
|
|
8
|
-
This document describes the
|
|
9
|
-
engine uses the same v3 stdio/WebRTC session path, with native display
|
|
10
|
-
input and clipboard adapters.
|
|
11
|
-
|
|
8
|
+
This document describes the Linux, macOS, and Windows engine protocol. The
|
|
9
|
+
macOS engine uses the same v3 stdio/WebRTC session path, with native display
|
|
10
|
+
capture, input and clipboard adapters. A Windows build with static libvpx
|
|
11
|
+
(`DESKLINK_VPX_STATIC_DIR`) also serves consumer-fed H.264 encoded sources over
|
|
12
|
+
the shared session path. Native desktop capture, input and clipboard are not
|
|
13
|
+
implemented on Windows, and `session.open` refuses `agent_indicator` with
|
|
14
|
+
`indicator-unavailable`. Without static libvpx, the Windows compile seam
|
|
15
|
+
reports encoding unavailable and refuses `serve`. The protocol contains no
|
|
16
|
+
application concepts: no accounts, no chat, no machine ids, no pane ids.
|
|
12
17
|
|
|
13
18
|
## Starting the engine
|
|
14
19
|
|
|
@@ -77,7 +82,7 @@ arrives, every other request is refused the same way; `capabilities` and
|
|
|
77
82
|
## macOS
|
|
78
83
|
|
|
79
84
|
For engine installation and the macOS resolution opt-out, see the
|
|
80
|
-
[host installation guide](../README.md#macos).
|
|
85
|
+
[host installation guide](../README.md#macos-preview).
|
|
81
86
|
|
|
82
87
|
macOS speaks protocol 3 and shares the session lifecycle below. It captures the
|
|
83
88
|
selected display with ScreenCaptureKit, encodes VP9 (and H.264 through
|
|
@@ -121,6 +126,8 @@ session may require fresh consent. The macOS engine requires a VP9-enabled build
|
|
|
121
126
|
"backends": ["portal-screencast+pipewire", "x11-root"],
|
|
122
127
|
"formats": ["bgrx", "bgra", "rgbx", "rgba"],
|
|
123
128
|
"cursor": "embedded",
|
|
129
|
+
"cursor_modes": ["embedded", "hidden"],
|
|
130
|
+
"cursor_positions": {"x11": true, "portal": "negotiated"},
|
|
124
131
|
"audio": false
|
|
125
132
|
},
|
|
126
133
|
"encode": {"codecs": ["vp9", "h264"], "hardware": false,
|
|
@@ -144,7 +151,11 @@ appears in `codecs` when an H.264 encoder starts on this machine right now, and
|
|
|
144
151
|
`encode.h264.encoder` names it: `videotoolbox` on macOS; on Linux `nvenc` or
|
|
145
152
|
`vaapi` when the GPU has an H.264 encoder, else `openh264`, Cisco's prebuilt
|
|
146
153
|
library. `encoder` is `null` when there is none. The answer to the offer picks
|
|
147
|
-
between them (see *Codecs* below).
|
|
154
|
+
between them (see *Codecs* below). Windows with static libvpx reports VP9 in
|
|
155
|
+
`encode.codecs`, but has no native desktop capture; without static libvpx its
|
|
156
|
+
`encode.codecs` is empty. On Windows, `encoded.codecs` reports H.264 only when
|
|
157
|
+
static libvpx is linked, for consumer-fed sources; it does not mean the engine
|
|
158
|
+
can encode H.264 itself.
|
|
148
159
|
|
|
149
160
|
openh264 is never part of this package: the engine loads only Cisco's own
|
|
150
161
|
binary, checked against its published SHA-256, from
|
|
@@ -457,6 +468,108 @@ named beside it for the per-frame mean:
|
|
|
457
468
|
frame within measurement noise; a stage that will not reconcile is a stage
|
|
458
469
|
whose accounting is wrong.
|
|
459
470
|
|
|
471
|
+
## Cursor-free capture
|
|
472
|
+
|
|
473
|
+
`session.open` accepts `cursor: "hidden"` (default `"embedded"`). Existing
|
|
474
|
+
callers keep their capture behavior. Linux hidden capture requires portal
|
|
475
|
+
**Metadata** so cursor positions remain available while cursor pixels are
|
|
476
|
+
omitted. A portal without Metadata returns the typed
|
|
477
|
+
`cursor_positions_unavailable` refusal. Successful open returns
|
|
478
|
+
`cursor: {"mode":"metadata"|"hidden"|"embedded"|"unavailable",
|
|
479
|
+
"positions":true|false}`; `mode` names the portal mode accepted by the portal,
|
|
480
|
+
not just the requested option.
|
|
481
|
+
|
|
482
|
+
Linux capabilities advertise `capture.cursor_modes: ["embedded","hidden"]`
|
|
483
|
+
and `capture.cursor_positions: {"x11":true,"portal":"negotiated"}`. Portal
|
|
484
|
+
support is resolved at open: hidden capture requires Metadata and an observed
|
|
485
|
+
SPA cursor metadata buffer. A portal that offers only Hidden refuses open with
|
|
486
|
+
`cursor_positions_unavailable`; accepted hidden sessions report `positions:true`.
|
|
487
|
+
Metadata-mode buffers that contain no new cursor data do not fabricate a move
|
|
488
|
+
or a visibility change.
|
|
489
|
+
|
|
490
|
+
Hidden sessions with positions emit local protocol events independently of
|
|
491
|
+
pixel damage, including on a still X11 desktop:
|
|
492
|
+
|
|
493
|
+
```json
|
|
494
|
+
{"event":"session.cursor","params":{"sessionId":"…","x":400,"y":300,"visible":true,"timestamp_us":123456}}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
`x,y` name the pointer hotspot in the selected source's coordinates
|
|
498
|
+
(`geometry.source`), before video scaling, without the desktop origin added.
|
|
499
|
+
Portal buffer coordinates are mapped to that geometry. `visible` is false
|
|
500
|
+
outside the source or when SPA supplies an invisible cursor bitmap.
|
|
501
|
+
`timestamp_us` is a monotonic engine-process clock in microseconds, sampled
|
|
502
|
+
when the capture thread observes the pointer. The same clock stamps
|
|
503
|
+
`session.frame.changed` and `session.frame` metadata, so local recording
|
|
504
|
+
consumers can compare cursor samples to frame handoff times. These are not
|
|
505
|
+
wall-clock or RTP timestamps. SPA cursor updates accompany PipeWire buffers;
|
|
506
|
+
X11 pointer queries run at the session frame cap even with no pixel damage.
|
|
507
|
+
Repeated identical positions/visibility are suppressed.
|
|
508
|
+
|
|
509
|
+
X11 root GetImage/MIT-SHM never contains the server cursor and this engine
|
|
510
|
+
never composites it, including for existing embedded-default callers. Its
|
|
511
|
+
open reply therefore reports `mode:"hidden"`; positions are enabled only by
|
|
512
|
+
an explicit `cursor:"hidden"`. macOS and Windows refuse hidden capture with
|
|
513
|
+
`cursor-unavailable` in this build. Consumer-fed encoded sources refuse it too:
|
|
514
|
+
the engine cannot remove pixels the consumer already encoded. Unknown cursor
|
|
515
|
+
options are `malformed`.
|
|
516
|
+
|
|
517
|
+
`@desklink/host` exposes `openSession({permissions:['view'], cursor:'hidden'})`
|
|
518
|
+
and typed `session.cursor` events through `onEvent`/`drainEvents`. The client
|
|
519
|
+
capture request also accepts `cursor`, and AXI accepts `start --cursor hidden`.
|
|
520
|
+
|
|
521
|
+
## Point on the host desktop
|
|
522
|
+
|
|
523
|
+
A local consumer can guide the person without taking control of their pointer
|
|
524
|
+
or keyboard. `session.point` requires `view`, not `control`, and is independent
|
|
525
|
+
of `agent_indicator`. It draws one blue ring centered at `x,y`, with an optional
|
|
526
|
+
label. A new point replaces the previous one and restarts its timer.
|
|
527
|
+
|
|
528
|
+
```jsonc
|
|
529
|
+
{"id":30,"method":"session.point","params":{"session_id":"…","x":400,"y":300,"label":"Here","timeout_ms":3000}}
|
|
530
|
+
{"id":30,"result":{"shown":true}}
|
|
531
|
+
{"id":31,"method":"session.point","params":{"session_id":"…","clear":true}}
|
|
532
|
+
{"id":31,"result":{"shown":false}}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Coordinates are integers in the **selected desktop's original pixels**, top-left
|
|
536
|
+
origin, before video scaling (`geometry.source`, not `geometry.encoded`). On X11
|
|
537
|
+
this is the root screen; on macOS it is the selected display, with native pixels
|
|
538
|
+
converted to display points. Both coordinates must be within its bounds. The
|
|
539
|
+
ring may clip at an edge; its label stays inside the display. `timeout_ms`
|
|
540
|
+
defaults to 3000 and must be an integer from 1 to 120000. Labels are at most 96
|
|
541
|
+
printable ASCII bytes, including spaces; other labels are refused rather than
|
|
542
|
+
rendered incorrectly by the X server's core font. A clear request has no
|
|
543
|
+
coordinates, label or timeout, and is idempotent. Invalid requests do not alter
|
|
544
|
+
an existing marker. Replies acknowledge submission to the local overlay helper,
|
|
545
|
+
not that a person has seen it. Timeout hides it; clear, session replacement,
|
|
546
|
+
lease expiry, close and consumer disconnection remove and reap the helper.
|
|
547
|
+
|
|
548
|
+
X11 uses an override-redirect, shaped window with an empty input shape. It never
|
|
549
|
+
warps the pointer, changes the cursor, requests focus or injects events. macOS
|
|
550
|
+
reuses the nonactivating, mouse-transparent indicator window in a separate
|
|
551
|
+
helper. **Point cues intentionally appear in local frames and outgoing video**:
|
|
552
|
+
the person and observer can see the same cue. They are separate from the
|
|
553
|
+
capture-excluded input activity indicator. Consumers reading frame differences
|
|
554
|
+
should allow for the point's appearance/disappearance.
|
|
555
|
+
|
|
556
|
+
Wayland portal sessions use a wlr-layer-shell overlay with no keyboard
|
|
557
|
+
interactivity and an empty input region. The selected monitor is matched by its
|
|
558
|
+
portal origin against compositor logical output geometry (xdg-output); with one
|
|
559
|
+
output, no origin is needed. Points map from the selected source to that output.
|
|
560
|
+
An ambiguous or missing selected output returns `indicator-unavailable`.
|
|
561
|
+
Compositors without layer-shell return `point_unsupported` with reason
|
|
562
|
+
`layer_shell_unavailable` (including GNOME Mutter). Consumer-fed encoded sources return `operation`
|
|
563
|
+
because they have no host desktop overlay target. Other refusals are `permission`, `session`,
|
|
564
|
+
`coordinates`, `malformed`, and `indicator-unavailable` (including unavailable
|
|
565
|
+
X Shape support). Unknown fields are refused. No control-channel or remote
|
|
566
|
+
bridge forwarding is added; the consumer chooses when to request a local cue.
|
|
567
|
+
|
|
568
|
+
`@desklink/host` exposes `EngineClient.point(sessionId, {x, y, label?, timeoutMs?})`
|
|
569
|
+
and `EngineClient.point(sessionId, {clear: true})`. `@desklink/axi` exposes
|
|
570
|
+
`desklink-axi point 400,300 --label "Here" --timeout 3000` and
|
|
571
|
+
`desklink-axi point --clear`, including for a session started without `--control`.
|
|
572
|
+
|
|
460
573
|
## Input and clipboard: the session's control channel
|
|
461
574
|
|
|
462
575
|
Input does **not** travel the local protocol. It rides the WebRTC data channel
|
package/engine/Cargo.lock
CHANGED
|
@@ -536,7 +536,7 @@ checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
|
536
536
|
|
|
537
537
|
[[package]]
|
|
538
538
|
name = "desklink-host"
|
|
539
|
-
version = "0.3.
|
|
539
|
+
version = "0.3.1"
|
|
540
540
|
dependencies = [
|
|
541
541
|
"anyhow",
|
|
542
542
|
"ashpd",
|
|
@@ -546,7 +546,6 @@ dependencies = [
|
|
|
546
546
|
"bytes",
|
|
547
547
|
"bzip2-rs",
|
|
548
548
|
"cc",
|
|
549
|
-
"futures-util",
|
|
550
549
|
"libc",
|
|
551
550
|
"log",
|
|
552
551
|
"objc2-core-foundation",
|
|
@@ -565,6 +564,7 @@ dependencies = [
|
|
|
565
564
|
"wayland-client",
|
|
566
565
|
"wayland-protocols",
|
|
567
566
|
"webrtc",
|
|
567
|
+
"windows-sys 0.61.2",
|
|
568
568
|
"wl-clipboard-rs",
|
|
569
569
|
"x11rb",
|
|
570
570
|
"xkbcommon",
|
package/engine/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "desklink-host"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.97.1"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -16,10 +16,9 @@ serde = { version = "1", features = ["derive"] }
|
|
|
16
16
|
serde_json = "1"
|
|
17
17
|
base64 = "0.22"
|
|
18
18
|
|
|
19
|
-
[target.'cfg(target_os = "linux")'.dependencies]
|
|
19
|
+
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))'.dependencies]
|
|
20
20
|
anyhow = "1"
|
|
21
21
|
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal"] }
|
|
22
|
-
futures-util = "0.3"
|
|
23
22
|
libc = "0.2"
|
|
24
23
|
bytes = "1"
|
|
25
24
|
webrtc = { version = "0.21", default-features = false, features = ["runtime-tokio", "crypto-ring"] }
|
|
@@ -27,6 +26,8 @@ rtc = { version = "0.21", default-features = false, features = ["crypto-ring"] }
|
|
|
27
26
|
log = "0.4"
|
|
28
27
|
async-trait = "0.1"
|
|
29
28
|
rand = "0.8"
|
|
29
|
+
|
|
30
|
+
[target.'cfg(target_os = "linux")'.dependencies]
|
|
30
31
|
ashpd = { version = "0.11", default-features = false, features = ["tokio"] }
|
|
31
32
|
pipewire = { version = "0.10", features = ["v0_3_44"] }
|
|
32
33
|
xkbcommon = "0.8"
|
|
@@ -43,16 +44,10 @@ bzip2-rs = "0.1.2"
|
|
|
43
44
|
wayland-client = "0.31"
|
|
44
45
|
wayland-protocols = { version = "0.32", features = ["client"] }
|
|
45
46
|
|
|
47
|
+
[target.'cfg(target_os = "windows")'.dependencies]
|
|
48
|
+
windows-sys = "0.61.2"
|
|
49
|
+
|
|
46
50
|
[target.'cfg(target_os = "macos")'.dependencies]
|
|
47
|
-
anyhow = "1"
|
|
48
|
-
async-trait = "0.1"
|
|
49
|
-
bytes = "1"
|
|
50
|
-
libc = "0.2"
|
|
51
|
-
log = "0.4"
|
|
52
|
-
rand = "0.8"
|
|
53
|
-
rtc = { version = "0.21", default-features = false, features = ["crypto-ring"] }
|
|
54
|
-
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal"] }
|
|
55
|
-
webrtc = { version = "0.21", default-features = false, features = ["runtime-tokio", "crypto-ring"] }
|
|
56
51
|
objc2-screen-capture-kit = { version = "0.3.2", features = ["SCStream", "SCShareableContent", "SCError", "SCScreenshotManager", "block2", "dispatch2", "objc2-core-media", "objc2-core-graphics"] }
|
|
57
52
|
objc2-foundation = { version = "0.3.2", features = ["NSArray", "NSError", "NSString"] }
|
|
58
53
|
objc2-core-media = "0.3.2"
|
package/engine/build.rs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
//! Native dependencies of the engine.
|
|
2
2
|
//!
|
|
3
|
-
//! The Linux build
|
|
4
|
-
//!
|
|
5
|
-
//! nothing is installed:
|
|
3
|
+
//! The Linux build compiles its native adapters from local sources and links
|
|
4
|
+
//! system libraries for desktop overlays — no prebuilt binary is fetched at
|
|
5
|
+
//! build time, and nothing is installed:
|
|
6
6
|
//!
|
|
7
7
|
//! * libvpx (BSD-3-Clause) — VP9 encode, through `native/vpx_shim.c` so the
|
|
8
8
|
//! versioned encoder config struct is laid out by a C compiler.
|
|
@@ -48,6 +48,44 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
48
48
|
println!("cargo:rerun-if-env-changed=DESKLINK_MACOS_CLI");
|
|
49
49
|
|
|
50
50
|
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
|
51
|
+
if target_os == "windows" {
|
|
52
|
+
if let Some(prefix) = std::env::var_os("DESKLINK_VPX_STATIC_DIR").map(PathBuf::from) {
|
|
53
|
+
if std::env::var("CARGO_CFG_TARGET_ENV")? != "msvc"
|
|
54
|
+
|| std::env::var("CARGO_CFG_TARGET_ARCH")? != "x86_64"
|
|
55
|
+
{
|
|
56
|
+
return Err("Windows libvpx requires x86_64-pc-windows-msvc".into());
|
|
57
|
+
}
|
|
58
|
+
if !std::env::var("CARGO_CFG_TARGET_FEATURE")?
|
|
59
|
+
.split(',')
|
|
60
|
+
.any(|f| f == "crt-static")
|
|
61
|
+
{
|
|
62
|
+
return Err(
|
|
63
|
+
"Windows static libvpx requires RUSTFLAGS=-Ctarget-feature=+crt-static (/MT)"
|
|
64
|
+
.into(),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if !prefix.join("include/vpx/vp8cx.h").is_file()
|
|
68
|
+
|| !prefix.join("lib/vpx.lib").is_file()
|
|
69
|
+
{
|
|
70
|
+
return Err(
|
|
71
|
+
"DESKLINK_VPX_STATIC_DIR must contain include/vpx/vp8cx.h and lib/vpx.lib"
|
|
72
|
+
.into(),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
cc::Build::new()
|
|
76
|
+
.file("native/vpx_shim.c")
|
|
77
|
+
.include(prefix.join("include"))
|
|
78
|
+
.static_crt(true)
|
|
79
|
+
.compile("dlvpx");
|
|
80
|
+
println!(
|
|
81
|
+
"cargo:rustc-link-search=native={}",
|
|
82
|
+
prefix.join("lib").display()
|
|
83
|
+
);
|
|
84
|
+
println!("cargo:rustc-link-lib=static=vpx");
|
|
85
|
+
println!("cargo:rustc-cfg=desklink_vpx");
|
|
86
|
+
}
|
|
87
|
+
return Ok(());
|
|
88
|
+
}
|
|
51
89
|
if let Some(prefix) = std::env::var_os("DESKLINK_VPX_STATIC_DIR").map(PathBuf::from) {
|
|
52
90
|
if !prefix.join("include/vpx/vp8cx.h").exists() || !prefix.join("lib/libvpx.a").exists() {
|
|
53
91
|
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());
|
|
@@ -90,11 +128,29 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
90
128
|
.include("vendor/libva")
|
|
91
129
|
.compile("dlvaapi");
|
|
92
130
|
println!("cargo:rustc-link-lib=dl");
|
|
93
|
-
cc::Build::new()
|
|
131
|
+
let mut overlay = cc::Build::new();
|
|
132
|
+
let includes = std::process::Command::new("pkg-config")
|
|
133
|
+
.args(["--cflags", "freetype2", "fontconfig"])
|
|
134
|
+
.output()?;
|
|
135
|
+
if !includes.status.success() {
|
|
136
|
+
return Err("FreeType and Fontconfig development headers are required".into());
|
|
137
|
+
}
|
|
138
|
+
for flag in String::from_utf8(includes.stdout)?.split_whitespace() {
|
|
139
|
+
overlay.flag(flag);
|
|
140
|
+
}
|
|
141
|
+
overlay
|
|
94
142
|
.file("native/agent_overlay_x11.c")
|
|
95
143
|
.file("native/agent_overlay_wayland.c")
|
|
96
144
|
.compile("dlagentoverlay");
|
|
97
|
-
for lib in [
|
|
145
|
+
for lib in [
|
|
146
|
+
"X11",
|
|
147
|
+
"Xext",
|
|
148
|
+
"Xcursor",
|
|
149
|
+
"wayland-client",
|
|
150
|
+
"fontconfig",
|
|
151
|
+
"freetype",
|
|
152
|
+
"m",
|
|
153
|
+
] {
|
|
98
154
|
println!("cargo:rustc-link-lib={lib}");
|
|
99
155
|
}
|
|
100
156
|
cc::Build::new()
|
|
@@ -3,18 +3,31 @@
|
|
|
3
3
|
#include <stdio.h>
|
|
4
4
|
#include <stdlib.h>
|
|
5
5
|
#include <unistd.h>
|
|
6
|
+
#include <string.h>
|
|
6
7
|
|
|
7
8
|
@interface AgentOverlayView : NSView {
|
|
8
9
|
NSPoint target, cursor;
|
|
9
10
|
CFTimeInterval clickAt, typeAt, endingAt;
|
|
10
11
|
BOOL positioned;
|
|
12
|
+
BOOL pointMode, pointVisible;
|
|
13
|
+
CFTimeInterval pointDeadline;
|
|
14
|
+
NSString *pointLabel;
|
|
11
15
|
}
|
|
12
16
|
- (void)event:(char)kind x:(double)x y:(double)y;
|
|
13
17
|
- (void)end;
|
|
18
|
+
- (void)enablePointMode;
|
|
19
|
+
- (void)pointX:(double)x y:(double)y timeout:(unsigned)timeout label:(NSString *)label;
|
|
14
20
|
@end
|
|
15
21
|
|
|
16
22
|
@implementation AgentOverlayView
|
|
17
23
|
- (BOOL)isOpaque { return NO; }
|
|
24
|
+
- (void)enablePointMode { pointMode = YES; }
|
|
25
|
+
- (void)pointX:(double)x y:(double)y timeout:(unsigned)timeout label:(NSString *)label {
|
|
26
|
+
cursor = NSMakePoint(x, self.bounds.size.height-y);
|
|
27
|
+
pointLabel = label; pointVisible = YES;
|
|
28
|
+
pointDeadline = CACurrentMediaTime() + timeout/1000.0;
|
|
29
|
+
[self setNeedsDisplay:YES];
|
|
30
|
+
}
|
|
18
31
|
- (void)event:(char)kind x:(double)x y:(double)y {
|
|
19
32
|
if (kind == 'S') { [self end]; return; }
|
|
20
33
|
if (x >= 0 && y >= 0) {
|
|
@@ -27,8 +40,12 @@
|
|
|
27
40
|
if (kind == 'T') typeAt = now;
|
|
28
41
|
[self setNeedsDisplay:YES];
|
|
29
42
|
}
|
|
30
|
-
- (void)end { endingAt = CACurrentMediaTime(); }
|
|
43
|
+
- (void)end { if (pointMode) { [NSApp terminate:nil]; return; } endingAt = CACurrentMediaTime(); }
|
|
31
44
|
- (void)tick {
|
|
45
|
+
if (pointMode) {
|
|
46
|
+
if (pointVisible && CACurrentMediaTime() >= pointDeadline) { pointVisible = NO; [self setNeedsDisplay:YES]; }
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
32
49
|
if (endingAt && CACurrentMediaTime() - endingAt > 0.7) { [NSApp terminate:nil]; return; }
|
|
33
50
|
cursor.x += (target.x - cursor.x) * 0.24;
|
|
34
51
|
cursor.y += (target.y - cursor.y) * 0.24;
|
|
@@ -36,6 +53,23 @@
|
|
|
36
53
|
}
|
|
37
54
|
- (void)drawRect:(NSRect)rect {
|
|
38
55
|
[[NSColor clearColor] set]; NSRectFillUsingOperation(rect, NSCompositingOperationCopy);
|
|
56
|
+
if (pointMode) {
|
|
57
|
+
if (!pointVisible) return;
|
|
58
|
+
[[NSColor colorWithCalibratedRed:0.30 green:0.62 blue:0.82 alpha:1] set];
|
|
59
|
+
NSBezierPath *ring = [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(cursor.x-18, cursor.y-18, 36, 36)];
|
|
60
|
+
ring.lineWidth = 4; [ring stroke];
|
|
61
|
+
[[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(cursor.x-3,cursor.y-3,6,6)] fill];
|
|
62
|
+
if (pointLabel.length) {
|
|
63
|
+
NSDictionary *style = @{NSFontAttributeName: [NSFont systemFontOfSize:13], NSForegroundColorAttributeName: NSColor.whiteColor};
|
|
64
|
+
NSSize size = [pointLabel sizeWithAttributes:style];
|
|
65
|
+
CGFloat x = fmax(0, fmin(cursor.x+30, self.bounds.size.width-size.width-16));
|
|
66
|
+
CGFloat y = fmax(0, fmin(cursor.y-14, self.bounds.size.height-28));
|
|
67
|
+
[[NSColor colorWithCalibratedRed:0.07 green:0.19 blue:0.28 alpha:1] set];
|
|
68
|
+
[[NSBezierPath bezierPathWithRoundedRect:NSMakeRect(x,y,size.width+16,28) xRadius:4 yRadius:4] fill];
|
|
69
|
+
[pointLabel drawAtPoint:NSMakePoint(x+8,y+6) withAttributes:style];
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
39
73
|
CFTimeInterval now = CACurrentMediaTime();
|
|
40
74
|
CGFloat edge = endingAt ? fmax(0, 1 - (now-endingAt)/0.7) : 1;
|
|
41
75
|
if (edge > 0) {
|
|
@@ -95,7 +129,7 @@ unsigned char *desklink_image_bgra(CGImageRef image, size_t *length, size_t *str
|
|
|
95
129
|
return pixels;
|
|
96
130
|
}
|
|
97
131
|
|
|
98
|
-
int
|
|
132
|
+
static int overlay_main(int display_id, BOOL point_mode) {
|
|
99
133
|
@autoreleasepool {
|
|
100
134
|
[NSApplication sharedApplication];
|
|
101
135
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
|
|
@@ -111,14 +145,24 @@ int desklink_agent_overlay_main(int display_id) {
|
|
|
111
145
|
window.collectionBehavior = NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary;
|
|
112
146
|
AgentOverlayView *view = [[AgentOverlayView alloc] initWithFrame:NSMakeRect(0,0,screen.frame.size.width,screen.frame.size.height)];
|
|
113
147
|
window.contentView = view;
|
|
148
|
+
if (point_mode) [view enablePointMode];
|
|
114
149
|
NSPoint mouse = [NSEvent mouseLocation];
|
|
115
|
-
[view event:'M' x:mouse.x-screen.frame.origin.x y:NSMaxY(screen.frame)-mouse.y];
|
|
150
|
+
if (!point_mode) [view event:'M' x:mouse.x-screen.frame.origin.x y:NSMaxY(screen.frame)-mouse.y];
|
|
116
151
|
[window orderFrontRegardless];
|
|
117
152
|
puts("READY"); fflush(stdout);
|
|
118
153
|
[NSTimer scheduledTimerWithTimeInterval:1.0/60 target:view selector:@selector(tick) userInfo:nil repeats:YES];
|
|
119
154
|
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
|
120
|
-
char line[
|
|
155
|
+
char line[512];
|
|
121
156
|
while (fgets(line, sizeof(line), stdin)) {
|
|
157
|
+
if (point_mode) {
|
|
158
|
+
double x, y; unsigned timeout; int offset = 0;
|
|
159
|
+
if (sscanf(line, "P %lf %lf %u %n", &x, &y, &timeout, &offset) == 3 && offset) {
|
|
160
|
+
line[strcspn(line, "\n")] = 0;
|
|
161
|
+
NSString *label = [NSString stringWithUTF8String:line+offset];
|
|
162
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [view pointX:x y:y timeout:timeout label:label]; });
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
122
166
|
char kind; double x = 0, y = 0;
|
|
123
167
|
if (sscanf(line, "%c %lf %lf", &kind, &x, &y) >= 1) {
|
|
124
168
|
dispatch_async(dispatch_get_main_queue(), ^{ [view event:kind x:x y:y]; });
|
|
@@ -131,3 +175,6 @@ int desklink_agent_overlay_main(int display_id) {
|
|
|
131
175
|
}
|
|
132
176
|
return 0;
|
|
133
177
|
}
|
|
178
|
+
|
|
179
|
+
int desklink_agent_overlay_main(int display_id) { return overlay_main(display_id, NO); }
|
|
180
|
+
int desklink_point_overlay_main(int display_id) { return overlay_main(display_id, YES); }
|