@yume-chan/scrcpy 0.0.20 → 0.0.22
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/CHANGELOG.json +33 -0
- package/CHANGELOG.md +18 -1
- package/README.md +8 -122
- package/esm/codec/av1.js +2 -2
- package/esm/codec/av1.js.map +1 -1
- package/esm/codec/h264.js +2 -2
- package/esm/codec/h264.js.map +1 -1
- package/esm/codec/h265.d.ts +72 -4
- package/esm/codec/h265.d.ts.map +1 -1
- package/esm/codec/h265.js +18 -19
- package/esm/codec/h265.js.map +1 -1
- package/esm/codec/nalu.d.ts +1 -8
- package/esm/codec/nalu.d.ts.map +1 -1
- package/esm/codec/nalu.js +53 -40
- package/esm/codec/nalu.js.map +1 -1
- package/esm/control/hover-helper.d.ts +1 -1
- package/esm/control/hover-helper.d.ts.map +1 -1
- package/esm/control/hover-helper.js +8 -9
- package/esm/control/hover-helper.js.map +1 -1
- package/esm/control/inject-keycode.d.ts +13 -13
- package/esm/control/inject-keycode.d.ts.map +1 -1
- package/esm/control/inject-keycode.js +3 -3
- package/esm/control/inject-keycode.js.map +1 -1
- package/esm/control/inject-touch.d.ts.map +1 -1
- package/esm/control/inject-touch.js +3 -4
- package/esm/control/inject-touch.js.map +1 -1
- package/esm/control/serializer.d.ts +4 -3
- package/esm/control/serializer.d.ts.map +1 -1
- package/esm/control/serializer.js +30 -14
- package/esm/control/serializer.js.map +1 -1
- package/esm/control/set-screen-power-mode.js +1 -1
- package/esm/control/set-screen-power-mode.js.map +1 -1
- package/esm/control/type.d.ts +1 -1
- package/esm/control/type.d.ts.map +1 -1
- package/esm/control/type.js +4 -4
- package/esm/control/type.js.map +1 -1
- package/esm/control/writer.d.ts +5 -3
- package/esm/control/writer.d.ts.map +1 -1
- package/esm/control/writer.js +23 -14
- package/esm/control/writer.js.map +1 -1
- package/esm/device-message/stream.js.map +1 -1
- package/esm/device-message/type.js +1 -1
- package/esm/device-message/type.js.map +1 -1
- package/esm/options/1_16/codec-options.d.ts +2 -2
- package/esm/options/1_16/codec-options.d.ts.map +1 -1
- package/esm/options/1_16/codec-options.js +15 -5
- package/esm/options/1_16/codec-options.js.map +1 -1
- package/esm/options/1_16/float-to-uint16.js.map +1 -1
- package/esm/options/1_16/init.js +2 -2
- package/esm/options/1_16/init.js.map +1 -1
- package/esm/options/1_16/options.d.ts +1 -1
- package/esm/options/1_16/options.d.ts.map +1 -1
- package/esm/options/1_16/options.js +2 -3
- package/esm/options/1_16/options.js.map +1 -1
- package/esm/options/1_16/scroll.d.ts +1 -2
- package/esm/options/1_16/scroll.d.ts.map +1 -1
- package/esm/options/1_16/scroll.js +12 -12
- package/esm/options/1_16/scroll.js.map +1 -1
- package/esm/options/1_17.d.ts +1 -1
- package/esm/options/1_17.d.ts.map +1 -1
- package/esm/options/1_17.js +1 -2
- package/esm/options/1_17.js.map +1 -1
- package/esm/options/1_18.d.ts +1 -1
- package/esm/options/1_18.d.ts.map +1 -1
- package/esm/options/1_18.js +3 -4
- package/esm/options/1_18.js.map +1 -1
- package/esm/options/1_21.d.ts +1 -1
- package/esm/options/1_21.d.ts.map +1 -1
- package/esm/options/1_21.js +1 -2
- package/esm/options/1_21.js.map +1 -1
- package/esm/options/1_22/options.d.ts +1 -1
- package/esm/options/1_22/options.d.ts.map +1 -1
- package/esm/options/1_22/options.js +1 -2
- package/esm/options/1_22/options.js.map +1 -1
- package/esm/options/1_22/scroll.d.ts.map +1 -1
- package/esm/options/1_22/scroll.js.map +1 -1
- package/esm/options/1_23.d.ts +1 -1
- package/esm/options/1_23.d.ts.map +1 -1
- package/esm/options/1_23.js +1 -2
- package/esm/options/1_23.js.map +1 -1
- package/esm/options/1_24.d.ts +1 -1
- package/esm/options/1_24.d.ts.map +1 -1
- package/esm/options/1_24.js +1 -2
- package/esm/options/1_24.js.map +1 -1
- package/esm/options/1_25/options.d.ts.map +1 -1
- package/esm/options/1_25/options.js.map +1 -1
- package/esm/options/2_0.d.ts +1 -1
- package/esm/options/2_0.d.ts.map +1 -1
- package/esm/options/2_0.js +2 -4
- package/esm/options/2_0.js.map +1 -1
- package/esm/options/2_1.d.ts +48 -0
- package/esm/options/2_1.d.ts.map +1 -0
- package/esm/options/2_1.js +23 -0
- package/esm/options/2_1.js.map +1 -0
- package/esm/options/2_2.d.ts +67 -0
- package/esm/options/2_2.d.ts.map +1 -0
- package/esm/options/2_2.js +44 -0
- package/esm/options/2_2.js.map +1 -0
- package/esm/options/codec.d.ts.map +1 -1
- package/esm/options/codec.js +3 -4
- package/esm/options/codec.js.map +1 -1
- package/esm/options/index.d.ts +2 -0
- package/esm/options/index.d.ts.map +1 -1
- package/esm/options/index.js +2 -0
- package/esm/options/index.js.map +1 -1
- package/esm/options/latest.d.ts +4 -5
- package/esm/options/latest.d.ts.map +1 -1
- package/esm/options/latest.js +2 -3
- package/esm/options/latest.js.map +1 -1
- package/esm/options/types.d.ts +1 -0
- package/esm/options/types.d.ts.map +1 -1
- package/esm/options/types.js +15 -0
- package/esm/options/types.js.map +1 -1
- package/package.json +10 -22
- package/src/codec/h265.ts +40 -31
- package/src/codec/nalu.ts +73 -55
- package/src/control/hover-helper.ts +10 -11
- package/src/control/inject-touch.ts +0 -1
- package/src/control/serializer.ts +56 -35
- package/src/control/type.ts +7 -7
- package/src/control/writer.ts +40 -30
- package/src/device-message/stream.ts +2 -2
- package/src/options/1_16/codec-options.ts +22 -7
- package/src/options/1_16/float-to-uint16.ts +1 -1
- package/src/options/1_16/options.ts +32 -36
- package/src/options/1_16/scroll.ts +16 -16
- package/src/options/1_17.ts +11 -11
- package/src/options/1_18.ts +12 -12
- package/src/options/1_21.ts +9 -9
- package/src/options/1_22/options.ts +7 -7
- package/src/options/1_22/scroll.ts +2 -2
- package/src/options/1_23.ts +6 -6
- package/src/options/1_24.ts +4 -4
- package/src/options/1_25/options.ts +4 -4
- package/src/options/1_25/scroll.ts +2 -2
- package/src/options/2_0.ts +25 -25
- package/src/options/2_1.ts +35 -0
- package/src/options/2_2.ts +68 -0
- package/src/options/codec.ts +13 -13
- package/src/options/index.ts +2 -0
- package/src/options/latest.ts +4 -6
- package/src/options/types.ts +47 -28
- package/tsconfig.build.tsbuildinfo +1 -1
- package/bin/scrcpy-server +0 -0
- package/bin/version.d.ts +0 -1
- package/bin/version.js +0 -1
- package/scripts/fetch-server.cjs +0 -38
|
@@ -15,34 +15,33 @@ import { ScrcpyControlMessageType } from "./type.js";
|
|
|
15
15
|
* so Scrcpy server can remove the previously hovering pointer.
|
|
16
16
|
*/
|
|
17
17
|
export class ScrcpyHoverHelper {
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
private lastHoverMessage: ScrcpyInjectTouchControlMessage | undefined;
|
|
18
|
+
// There can be only one hovering pointer (either mouse or pen,
|
|
19
|
+
// touch can have multiple pointers but no hovering state).
|
|
20
|
+
#lastHoverMessage: ScrcpyInjectTouchControlMessage | undefined;
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
message: Omit<ScrcpyInjectTouchControlMessage, "type"
|
|
22
|
+
process(
|
|
23
|
+
message: Omit<ScrcpyInjectTouchControlMessage, "type">,
|
|
25
24
|
): ScrcpyInjectTouchControlMessage[] {
|
|
26
25
|
const result: ScrcpyInjectTouchControlMessage[] = [];
|
|
27
26
|
|
|
28
27
|
// A different pointer appeared,
|
|
29
28
|
// Cancel previously hovering pointer so Scrcpy server can free up the pointer ID.
|
|
30
29
|
if (
|
|
31
|
-
this
|
|
32
|
-
this
|
|
30
|
+
this.#lastHoverMessage &&
|
|
31
|
+
this.#lastHoverMessage.pointerId !== message.pointerId
|
|
33
32
|
) {
|
|
34
33
|
// TODO: Inject MotionEvent.ACTION_HOVER_EXIT
|
|
35
34
|
// From testing, it seems no App cares about this event.
|
|
36
35
|
result.push({
|
|
37
|
-
...this
|
|
36
|
+
...this.#lastHoverMessage,
|
|
38
37
|
action: AndroidMotionEventAction.Up,
|
|
39
38
|
});
|
|
40
|
-
this
|
|
39
|
+
this.#lastHoverMessage = undefined;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
if (message.action === AndroidMotionEventAction.HoverMove) {
|
|
44
43
|
// TODO: Inject MotionEvent.ACTION_HOVER_ENTER
|
|
45
|
-
this
|
|
44
|
+
this.#lastHoverMessage = message as ScrcpyInjectTouchControlMessage;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
(message as ScrcpyInjectTouchControlMessage).type =
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
ScrcpyScrollController,
|
|
4
4
|
} from "../options/index.js";
|
|
5
5
|
|
|
6
|
+
import { BasicControlMessage } from "./basic.js";
|
|
6
7
|
import type { AndroidKeyEventAction } from "./inject-keycode.js";
|
|
7
8
|
import { ScrcpyInjectKeyCodeControlMessage } from "./inject-keycode.js";
|
|
8
9
|
import type { ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
|
|
@@ -17,79 +18,99 @@ import {
|
|
|
17
18
|
} from "./type.js";
|
|
18
19
|
|
|
19
20
|
export class ScrcpyControlMessageSerializer {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
#options: ScrcpyOptions<object>;
|
|
22
|
+
#typeValues: ScrcpyControlMessageTypeValue;
|
|
23
|
+
#scrollController: ScrcpyScrollController;
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
this
|
|
26
|
-
this
|
|
27
|
-
this
|
|
25
|
+
constructor(options: ScrcpyOptions<object>) {
|
|
26
|
+
this.#options = options;
|
|
27
|
+
this.#typeValues = new ScrcpyControlMessageTypeValue(options);
|
|
28
|
+
this.#scrollController = options.createScrollController();
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">
|
|
32
|
-
) {
|
|
31
|
+
injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">) {
|
|
33
32
|
return ScrcpyInjectKeyCodeControlMessage.serialize(
|
|
34
|
-
this.
|
|
33
|
+
this.#typeValues.fillMessageType(
|
|
35
34
|
message,
|
|
36
|
-
ScrcpyControlMessageType.InjectKeyCode
|
|
37
|
-
)
|
|
35
|
+
ScrcpyControlMessageType.InjectKeyCode,
|
|
36
|
+
),
|
|
38
37
|
);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
injectText(text: string) {
|
|
42
41
|
return ScrcpyInjectTextControlMessage.serialize({
|
|
43
42
|
text,
|
|
44
|
-
type: this.
|
|
43
|
+
type: this.#typeValues.get(ScrcpyControlMessageType.InjectText),
|
|
45
44
|
});
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
/**
|
|
49
48
|
* `pressure` is a float value between 0 and 1.
|
|
50
49
|
*/
|
|
51
|
-
|
|
52
|
-
return this.
|
|
53
|
-
this.
|
|
50
|
+
injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
|
|
51
|
+
return this.#options.serializeInjectTouchControlMessage(
|
|
52
|
+
this.#typeValues.fillMessageType(
|
|
54
53
|
message,
|
|
55
|
-
ScrcpyControlMessageType.InjectTouch
|
|
56
|
-
)
|
|
54
|
+
ScrcpyControlMessageType.InjectTouch,
|
|
55
|
+
),
|
|
57
56
|
);
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
/**
|
|
61
60
|
* `scrollX` and `scrollY` are float values between 0 and 1.
|
|
62
61
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return this._scrollController.serializeScrollMessage(
|
|
67
|
-
this._typeValues.fillMessageType(
|
|
62
|
+
injectScroll(message: Omit<ScrcpyInjectScrollControlMessage, "type">) {
|
|
63
|
+
return this.#scrollController.serializeScrollMessage(
|
|
64
|
+
this.#typeValues.fillMessageType(
|
|
68
65
|
message,
|
|
69
|
-
ScrcpyControlMessageType.InjectScroll
|
|
70
|
-
)
|
|
66
|
+
ScrcpyControlMessageType.InjectScroll,
|
|
67
|
+
),
|
|
71
68
|
);
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
return this.
|
|
71
|
+
backOrScreenOn(action: AndroidKeyEventAction) {
|
|
72
|
+
return this.#options.serializeBackOrScreenOnControlMessage({
|
|
76
73
|
action,
|
|
77
|
-
type: this.
|
|
74
|
+
type: this.#typeValues.get(ScrcpyControlMessageType.BackOrScreenOn),
|
|
78
75
|
});
|
|
79
76
|
}
|
|
80
77
|
|
|
81
|
-
|
|
78
|
+
setScreenPowerMode(mode: AndroidScreenPowerMode) {
|
|
82
79
|
return ScrcpySetScreenPowerModeControlMessage.serialize({
|
|
83
80
|
mode,
|
|
84
|
-
type: this.
|
|
85
|
-
ScrcpyControlMessageType.SetScreenPowerMode
|
|
81
|
+
type: this.#typeValues.get(
|
|
82
|
+
ScrcpyControlMessageType.SetScreenPowerMode,
|
|
83
|
+
),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
expandNotificationPanel() {
|
|
88
|
+
return BasicControlMessage.serialize({
|
|
89
|
+
type: this.#typeValues.get(
|
|
90
|
+
ScrcpyControlMessageType.ExpandNotificationPanel,
|
|
91
|
+
),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
expandSettingPanel() {
|
|
96
|
+
return BasicControlMessage.serialize({
|
|
97
|
+
type: this.#typeValues.get(
|
|
98
|
+
ScrcpyControlMessageType.ExpandSettingPanel,
|
|
99
|
+
),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
collapseNotificationPanel() {
|
|
104
|
+
return BasicControlMessage.serialize({
|
|
105
|
+
type: this.#typeValues.get(
|
|
106
|
+
ScrcpyControlMessageType.CollapseNotificationPanel,
|
|
86
107
|
),
|
|
87
108
|
});
|
|
88
109
|
}
|
|
89
110
|
|
|
90
|
-
|
|
111
|
+
rotateDevice() {
|
|
91
112
|
return ScrcpyRotateDeviceControlMessage.serialize({
|
|
92
|
-
type: this.
|
|
113
|
+
type: this.#typeValues.get(ScrcpyControlMessageType.RotateDevice),
|
|
93
114
|
});
|
|
94
115
|
}
|
|
95
116
|
}
|
package/src/control/type.ts
CHANGED
|
@@ -25,23 +25,23 @@ export enum ScrcpyControlMessageType {
|
|
|
25
25
|
* This class provides a way to get the actual value for a given type.
|
|
26
26
|
*/
|
|
27
27
|
export class ScrcpyControlMessageTypeValue {
|
|
28
|
-
|
|
28
|
+
#types: readonly ScrcpyControlMessageType[];
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
this
|
|
30
|
+
constructor(options: ScrcpyOptions<object>) {
|
|
31
|
+
this.#types = options.controlMessageTypes;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
const value = this
|
|
34
|
+
get(type: ScrcpyControlMessageType): number {
|
|
35
|
+
const value = this.#types.indexOf(type);
|
|
36
36
|
if (value === -1) {
|
|
37
37
|
throw new Error("Not supported");
|
|
38
38
|
}
|
|
39
39
|
return value;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
fillMessageType<T extends { type: ScrcpyControlMessageType }>(
|
|
43
43
|
message: Omit<T, "type">,
|
|
44
|
-
type: T["type"]
|
|
44
|
+
type: T["type"],
|
|
45
45
|
): T {
|
|
46
46
|
(message as T).type = this.get(type);
|
|
47
47
|
return message as T;
|
package/src/control/writer.ts
CHANGED
|
@@ -16,72 +16,82 @@ import { ScrcpyControlMessageSerializer } from "./serializer.js";
|
|
|
16
16
|
import type { AndroidScreenPowerMode } from "./set-screen-power-mode.js";
|
|
17
17
|
|
|
18
18
|
export class ScrcpyControlMessageWriter {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
#writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
|
|
20
|
+
#serializer: ScrcpyControlMessageSerializer;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
constructor(
|
|
23
23
|
writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
|
|
24
|
-
options: ScrcpyOptions<object
|
|
24
|
+
options: ScrcpyOptions<object>,
|
|
25
25
|
) {
|
|
26
|
-
this
|
|
27
|
-
this
|
|
26
|
+
this.#writer = writer;
|
|
27
|
+
this.#serializer = new ScrcpyControlMessageSerializer(options);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
await ConsumableWritableStream.write(this
|
|
30
|
+
async write(message: Uint8Array) {
|
|
31
|
+
await ConsumableWritableStream.write(this.#writer, message);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
message: Omit<ScrcpyInjectKeyCodeControlMessage, "type"
|
|
34
|
+
async injectKeyCode(
|
|
35
|
+
message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">,
|
|
36
36
|
) {
|
|
37
|
-
await this.write(this.
|
|
37
|
+
await this.write(this.#serializer.injectKeyCode(message));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
await this.write(this.
|
|
40
|
+
async injectText(text: string) {
|
|
41
|
+
await this.write(this.#serializer.injectText(text));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* `pressure` is a float value between 0 and 1.
|
|
46
46
|
*/
|
|
47
|
-
|
|
48
|
-
message
|
|
49
|
-
) {
|
|
50
|
-
await this.write(this._serializer.injectTouch(message));
|
|
47
|
+
async injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
|
|
48
|
+
await this.write(this.#serializer.injectTouch(message));
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
/**
|
|
54
52
|
* `scrollX` and `scrollY` are float values between 0 and 1.
|
|
55
53
|
*/
|
|
56
|
-
|
|
57
|
-
message: Omit<ScrcpyInjectScrollControlMessage, "type"
|
|
54
|
+
async injectScroll(
|
|
55
|
+
message: Omit<ScrcpyInjectScrollControlMessage, "type">,
|
|
58
56
|
) {
|
|
59
|
-
const data = this.
|
|
57
|
+
const data = this.#serializer.injectScroll(message);
|
|
60
58
|
if (data) {
|
|
61
59
|
await this.write(data);
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
const data = this.
|
|
63
|
+
async backOrScreenOn(action: AndroidKeyEventAction) {
|
|
64
|
+
const data = this.#serializer.backOrScreenOn(action);
|
|
67
65
|
if (data) {
|
|
68
66
|
await this.write(data);
|
|
69
67
|
}
|
|
70
68
|
}
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
await this.write(this.
|
|
70
|
+
async setScreenPowerMode(mode: AndroidScreenPowerMode) {
|
|
71
|
+
await this.write(this.#serializer.setScreenPowerMode(mode));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async expandNotificationPanel() {
|
|
75
|
+
await this.write(this.#serializer.expandNotificationPanel());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async expandSettingPanel() {
|
|
79
|
+
await this.write(this.#serializer.expandSettingPanel());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async collapseNotificationPanel() {
|
|
83
|
+
await this.write(this.#serializer.collapseNotificationPanel());
|
|
74
84
|
}
|
|
75
85
|
|
|
76
|
-
|
|
77
|
-
await this.write(this.
|
|
86
|
+
async rotateDevice() {
|
|
87
|
+
await this.write(this.#serializer.rotateDevice());
|
|
78
88
|
}
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
this.
|
|
90
|
+
releaseLock() {
|
|
91
|
+
this.#writer.releaseLock();
|
|
82
92
|
}
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
await this.
|
|
94
|
+
async close() {
|
|
95
|
+
await this.#writer.close();
|
|
86
96
|
}
|
|
87
97
|
}
|
|
@@ -21,11 +21,11 @@ export class ScrcpyDeviceMessageDeserializeStream extends BufferedTransformStrea
|
|
|
21
21
|
switch (type[0]) {
|
|
22
22
|
case ScrcpyDeviceMessageType.Clipboard:
|
|
23
23
|
return await ScrcpyClipboardDeviceMessage.deserialize(
|
|
24
|
-
stream
|
|
24
|
+
stream,
|
|
25
25
|
);
|
|
26
26
|
case ScrcpyDeviceMessageType.AckClipboard:
|
|
27
27
|
return await ScrcpyAckClipboardDeviceMessage.deserialize(
|
|
28
|
-
stream
|
|
28
|
+
stream,
|
|
29
29
|
);
|
|
30
30
|
default:
|
|
31
31
|
throw new Error("Unsupported control message type");
|
|
@@ -27,15 +27,23 @@ const CODEC_OPTION_TYPES: Partial<
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
export class CodecOptions implements ScrcpyOptionValue {
|
|
30
|
-
|
|
30
|
+
options: Partial<CodecOptionsInit>;
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
constructor(options: Partial<CodecOptionsInit> = {}) {
|
|
33
|
+
for (const [key, value] of Object.entries(options)) {
|
|
34
|
+
if (typeof value !== "number") {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Invalid option value for ${key}: ${String(value)}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.options = options;
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
const entries = Object.entries(this.
|
|
38
|
-
([, value]) => value !== undefined
|
|
44
|
+
toOptionValue(): string | undefined {
|
|
45
|
+
const entries = Object.entries(this.options).filter(
|
|
46
|
+
([, value]) => value !== undefined,
|
|
39
47
|
);
|
|
40
48
|
|
|
41
49
|
if (entries.length === 0) {
|
|
@@ -44,8 +52,15 @@ export class CodecOptions implements ScrcpyOptionValue {
|
|
|
44
52
|
|
|
45
53
|
return entries
|
|
46
54
|
.map(([key, value]) => {
|
|
55
|
+
let result = toDashCase(key);
|
|
56
|
+
|
|
47
57
|
const type = CODEC_OPTION_TYPES[key as keyof CodecOptionsInit];
|
|
48
|
-
|
|
58
|
+
if (type) {
|
|
59
|
+
result += `:${type}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
result += `=${value}`;
|
|
63
|
+
return result;
|
|
49
64
|
})
|
|
50
65
|
.join(",");
|
|
51
66
|
}
|
|
@@ -38,14 +38,14 @@ import type { ScrcpyScrollController } from "./scroll.js";
|
|
|
38
38
|
import { ScrcpyScrollController1_16 } from "./scroll.js";
|
|
39
39
|
|
|
40
40
|
export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
41
|
-
|
|
41
|
+
static readonly DEFAULTS = {
|
|
42
42
|
logLevel: ScrcpyLogLevel1_16.Debug,
|
|
43
43
|
maxSize: 0,
|
|
44
44
|
bitRate: 8_000_000,
|
|
45
45
|
maxFps: 0,
|
|
46
46
|
lockVideoOrientation: ScrcpyVideoOrientation1_16.Unlocked,
|
|
47
47
|
tunnelForward: false,
|
|
48
|
-
crop:
|
|
48
|
+
crop: "",
|
|
49
49
|
sendFrameMeta: true,
|
|
50
50
|
control: true,
|
|
51
51
|
displayId: 0,
|
|
@@ -54,7 +54,7 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
54
54
|
codecOptions: new CodecOptions(),
|
|
55
55
|
} as const satisfies Required<ScrcpyOptionsInit1_16>;
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
static readonly SERIALIZE_ORDER = [
|
|
58
58
|
"logLevel",
|
|
59
59
|
"maxSize",
|
|
60
60
|
"bitRate",
|
|
@@ -70,68 +70,64 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
70
70
|
"codecOptions",
|
|
71
71
|
] as const satisfies readonly (keyof ScrcpyOptionsInit1_16)[];
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
static serialize<T>(options: T, order: readonly (keyof T)[]) {
|
|
74
74
|
return order.map((key) => toScrcpyOptionValue(options[key], "-"));
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
static async parseCString(
|
|
78
78
|
stream: AsyncExactReadable,
|
|
79
|
-
maxLength: number
|
|
79
|
+
maxLength: number,
|
|
80
80
|
): Promise<string> {
|
|
81
81
|
let result = decodeUtf8(await stream.readExactly(maxLength));
|
|
82
82
|
result = result.substring(0, result.indexOf("\0"));
|
|
83
83
|
return result;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
stream: AsyncExactReadable
|
|
88
|
-
): Promise<number> {
|
|
86
|
+
static async parseUint16BE(stream: AsyncExactReadable): Promise<number> {
|
|
89
87
|
const buffer = await stream.readExactly(NumberFieldType.Uint16.size);
|
|
90
88
|
return NumberFieldType.Uint16.deserialize(buffer, false);
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
stream: AsyncExactReadable
|
|
95
|
-
): Promise<number> {
|
|
91
|
+
static async parseUint32BE(stream: AsyncExactReadable): Promise<number> {
|
|
96
92
|
const buffer = await stream.readExactly(NumberFieldType.Uint32.size);
|
|
97
93
|
return NumberFieldType.Uint32.deserialize(buffer, false);
|
|
98
94
|
}
|
|
99
95
|
|
|
100
|
-
|
|
96
|
+
value: Required<ScrcpyOptionsInit1_16>;
|
|
101
97
|
|
|
102
|
-
|
|
98
|
+
readonly defaults: Required<ScrcpyOptionsInit1_16> =
|
|
103
99
|
ScrcpyOptions1_16.DEFAULTS;
|
|
104
100
|
|
|
105
|
-
|
|
101
|
+
readonly controlMessageTypes: readonly ScrcpyControlMessageType[] =
|
|
106
102
|
SCRCPY_CONTROL_MESSAGE_TYPES_1_16;
|
|
107
103
|
|
|
108
|
-
|
|
104
|
+
constructor(init: ScrcpyOptionsInit1_16) {
|
|
109
105
|
this.value = { ...ScrcpyOptions1_16.DEFAULTS, ...init };
|
|
110
106
|
}
|
|
111
107
|
|
|
112
|
-
|
|
108
|
+
serialize(): string[] {
|
|
113
109
|
return ScrcpyOptions1_16.serialize(
|
|
114
110
|
this.value,
|
|
115
|
-
ScrcpyOptions1_16.SERIALIZE_ORDER
|
|
111
|
+
ScrcpyOptions1_16.SERIALIZE_ORDER,
|
|
116
112
|
);
|
|
117
113
|
}
|
|
118
114
|
|
|
119
|
-
|
|
115
|
+
setListEncoders(): void {
|
|
120
116
|
throw new Error("Not supported");
|
|
121
117
|
}
|
|
122
118
|
|
|
123
|
-
|
|
119
|
+
setListDisplays(): void {
|
|
124
120
|
// Set to an invalid value
|
|
125
121
|
// Server will print valid values before crashing
|
|
126
122
|
// (server will crash before opening sockets)
|
|
127
123
|
this.value.displayId = -1;
|
|
128
124
|
}
|
|
129
125
|
|
|
130
|
-
|
|
126
|
+
parseEncoder(): ScrcpyEncoder | undefined {
|
|
131
127
|
throw new Error("Not supported");
|
|
132
128
|
}
|
|
133
129
|
|
|
134
|
-
|
|
130
|
+
parseDisplay(line: string): ScrcpyDisplay | undefined {
|
|
135
131
|
const displayIdRegex = /\s+scrcpy --display (\d+)/;
|
|
136
132
|
const match = line.match(displayIdRegex);
|
|
137
133
|
if (match) {
|
|
@@ -142,8 +138,8 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
142
138
|
return undefined;
|
|
143
139
|
}
|
|
144
140
|
|
|
145
|
-
|
|
146
|
-
stream: ReadableStream<Uint8Array
|
|
141
|
+
parseVideoStreamMetadata(
|
|
142
|
+
stream: ReadableStream<Uint8Array>,
|
|
147
143
|
): ValueOrPromise<ScrcpyVideoStream> {
|
|
148
144
|
return (async () => {
|
|
149
145
|
const buffered = new BufferedReadableStream(stream);
|
|
@@ -152,7 +148,7 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
152
148
|
};
|
|
153
149
|
metadata.deviceName = await ScrcpyOptions1_16.parseCString(
|
|
154
150
|
buffered,
|
|
155
|
-
64
|
|
151
|
+
64,
|
|
156
152
|
);
|
|
157
153
|
metadata.width = await ScrcpyOptions1_16.parseUint16BE(buffered);
|
|
158
154
|
metadata.height = await ScrcpyOptions1_16.parseUint16BE(buffered);
|
|
@@ -160,11 +156,11 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
160
156
|
})();
|
|
161
157
|
}
|
|
162
158
|
|
|
163
|
-
|
|
159
|
+
parseAudioStreamMetadata(): never {
|
|
164
160
|
throw new Error("Not supported");
|
|
165
161
|
}
|
|
166
162
|
|
|
167
|
-
|
|
163
|
+
createMediaStreamTransformer(): TransformStream<
|
|
168
164
|
Uint8Array,
|
|
169
165
|
ScrcpyMediaStreamPacket
|
|
170
166
|
> {
|
|
@@ -181,7 +177,7 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
181
177
|
}
|
|
182
178
|
|
|
183
179
|
const deserializeStream = new StructDeserializeStream(
|
|
184
|
-
ScrcpyMediaStreamRawPacket
|
|
180
|
+
ScrcpyMediaStreamRawPacket,
|
|
185
181
|
);
|
|
186
182
|
return {
|
|
187
183
|
writable: deserializeStream.writable,
|
|
@@ -202,19 +198,19 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
202
198
|
data: packet.data,
|
|
203
199
|
});
|
|
204
200
|
},
|
|
205
|
-
})
|
|
201
|
+
}),
|
|
206
202
|
),
|
|
207
203
|
};
|
|
208
204
|
}
|
|
209
205
|
|
|
210
|
-
|
|
211
|
-
message: ScrcpyInjectTouchControlMessage
|
|
206
|
+
serializeInjectTouchControlMessage(
|
|
207
|
+
message: ScrcpyInjectTouchControlMessage,
|
|
212
208
|
): Uint8Array {
|
|
213
209
|
return ScrcpyInjectTouchControlMessage1_16.serialize(message);
|
|
214
210
|
}
|
|
215
211
|
|
|
216
|
-
|
|
217
|
-
message: ScrcpyBackOrScreenOnControlMessage
|
|
212
|
+
serializeBackOrScreenOnControlMessage(
|
|
213
|
+
message: ScrcpyBackOrScreenOnControlMessage,
|
|
218
214
|
) {
|
|
219
215
|
if (message.action === AndroidKeyEventAction.Down) {
|
|
220
216
|
return ScrcpyBackOrScreenOnControlMessage1_16.serialize(message);
|
|
@@ -223,13 +219,13 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
|
|
223
219
|
return undefined;
|
|
224
220
|
}
|
|
225
221
|
|
|
226
|
-
|
|
227
|
-
message: ScrcpySetClipboardControlMessage
|
|
222
|
+
serializeSetClipboardControlMessage(
|
|
223
|
+
message: ScrcpySetClipboardControlMessage,
|
|
228
224
|
): Uint8Array {
|
|
229
225
|
return ScrcpySetClipboardControlMessage1_15.serialize(message);
|
|
230
226
|
}
|
|
231
227
|
|
|
232
|
-
|
|
228
|
+
createScrollController(): ScrcpyScrollController {
|
|
233
229
|
return new ScrcpyScrollController1_16();
|
|
234
230
|
}
|
|
235
231
|
}
|
|
@@ -4,7 +4,7 @@ import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
|
|
|
4
4
|
|
|
5
5
|
export interface ScrcpyScrollController {
|
|
6
6
|
serializeScrollMessage(
|
|
7
|
-
message: ScrcpyInjectScrollControlMessage
|
|
7
|
+
message: ScrcpyInjectScrollControlMessage,
|
|
8
8
|
): Uint8Array | undefined;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -24,31 +24,31 @@ export const ScrcpyInjectScrollControlMessage1_16 = new Struct()
|
|
|
24
24
|
* reaches 1 or -1.
|
|
25
25
|
*/
|
|
26
26
|
export class ScrcpyScrollController1_16 implements ScrcpyScrollController {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
#accumulatedX = 0;
|
|
28
|
+
#accumulatedY = 0;
|
|
29
29
|
|
|
30
30
|
protected processMessage(
|
|
31
|
-
message: ScrcpyInjectScrollControlMessage
|
|
31
|
+
message: ScrcpyInjectScrollControlMessage,
|
|
32
32
|
): ScrcpyInjectScrollControlMessage | undefined {
|
|
33
|
-
this
|
|
34
|
-
this
|
|
33
|
+
this.#accumulatedX += message.scrollX;
|
|
34
|
+
this.#accumulatedY += message.scrollY;
|
|
35
35
|
|
|
36
36
|
let scrollX = 0;
|
|
37
37
|
let scrollY = 0;
|
|
38
|
-
if (this
|
|
38
|
+
if (this.#accumulatedX >= 1) {
|
|
39
39
|
scrollX = 1;
|
|
40
|
-
this
|
|
41
|
-
} else if (this
|
|
40
|
+
this.#accumulatedX = 0;
|
|
41
|
+
} else if (this.#accumulatedX <= -1) {
|
|
42
42
|
scrollX = -1;
|
|
43
|
-
this
|
|
43
|
+
this.#accumulatedX = 0;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
if (this
|
|
46
|
+
if (this.#accumulatedY >= 1) {
|
|
47
47
|
scrollY = 1;
|
|
48
|
-
this
|
|
49
|
-
} else if (this
|
|
48
|
+
this.#accumulatedY = 0;
|
|
49
|
+
} else if (this.#accumulatedY <= -1) {
|
|
50
50
|
scrollY = -1;
|
|
51
|
-
this
|
|
51
|
+
this.#accumulatedY = 0;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (scrollX === 0 && scrollY === 0) {
|
|
@@ -60,8 +60,8 @@ export class ScrcpyScrollController1_16 implements ScrcpyScrollController {
|
|
|
60
60
|
return message;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
message: ScrcpyInjectScrollControlMessage
|
|
63
|
+
serializeScrollMessage(
|
|
64
|
+
message: ScrcpyInjectScrollControlMessage,
|
|
65
65
|
): Uint8Array | undefined {
|
|
66
66
|
const processed = this.processMessage(message);
|
|
67
67
|
if (!processed) {
|