@yume-chan/scrcpy 0.0.17 → 0.0.18
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 +21 -3
- package/CHANGELOG.md +13 -4
- package/LICENSE +1 -1
- package/README.md +41 -24
- package/bin/scrcpy-server +0 -0
- package/bin/version.d.ts +1 -1
- package/bin/version.js +1 -1
- package/esm/adb/client.d.ts +15 -14
- package/esm/adb/client.d.ts.map +1 -1
- package/esm/adb/client.js +66 -41
- package/esm/adb/client.js.map +1 -1
- package/esm/adb/connection.d.ts +16 -7
- package/esm/adb/connection.d.ts.map +1 -1
- package/esm/adb/connection.js +21 -13
- package/esm/adb/connection.js.map +1 -1
- package/esm/adb/options/1_16.d.ts +4 -4
- package/esm/adb/options/1_16.d.ts.map +1 -1
- package/esm/adb/options/1_16.js +2 -2
- package/esm/adb/options/1_16.js.map +1 -1
- package/esm/adb/options/1_22.d.ts +4 -4
- package/esm/adb/options/1_22.d.ts.map +1 -1
- package/esm/adb/options/1_22.js +2 -2
- package/esm/adb/options/1_22.js.map +1 -1
- package/esm/adb/options/types.d.ts +10 -9
- package/esm/adb/options/types.d.ts.map +1 -1
- package/esm/adb/options/types.js +11 -4
- package/esm/adb/options/types.js.map +1 -1
- package/esm/control/back-or-screen-on.d.ts +3 -0
- package/esm/control/back-or-screen-on.d.ts.map +1 -0
- package/esm/control/back-or-screen-on.js +2 -0
- package/esm/control/back-or-screen-on.js.map +1 -0
- package/esm/control/hover-helper.d.ts +18 -0
- package/esm/control/hover-helper.d.ts.map +1 -0
- package/esm/control/hover-helper.js +44 -0
- package/esm/control/hover-helper.js.map +1 -0
- package/esm/control/index.d.ts +11 -7
- package/esm/control/index.d.ts.map +1 -1
- package/esm/control/index.js +11 -7
- package/esm/control/index.js.map +1 -1
- package/esm/control/inject-keycode.d.ts +12 -4
- package/esm/control/inject-keycode.d.ts.map +1 -1
- package/esm/control/inject-keycode.js +15 -7
- package/esm/control/inject-keycode.js.map +1 -1
- package/esm/control/inject-scroll.d.ts +3 -0
- package/esm/control/inject-scroll.d.ts.map +1 -0
- package/esm/control/inject-scroll.js +2 -0
- package/esm/control/inject-scroll.js.map +1 -0
- package/esm/control/inject-text.d.ts +2 -2
- package/esm/control/inject-text.d.ts.map +1 -1
- package/esm/control/inject-touch.d.ts +12 -4
- package/esm/control/inject-touch.d.ts.map +1 -1
- package/esm/control/inject-touch.js +44 -11
- package/esm/control/inject-touch.js.map +1 -1
- package/esm/control/rotate-device.d.ts +2 -2
- package/esm/control/rotate-device.d.ts.map +1 -1
- package/esm/control/serializer.d.ts +22 -11
- package/esm/control/serializer.d.ts.map +1 -1
- package/esm/control/serializer.js +32 -26
- package/esm/control/serializer.js.map +1 -1
- package/esm/control/set-clipboard.d.ts +3 -0
- package/esm/control/set-clipboard.d.ts.map +1 -0
- package/esm/control/set-clipboard.js +2 -0
- package/esm/control/set-clipboard.js.map +1 -0
- package/esm/control/set-screen-power-mode.d.ts +2 -2
- package/esm/control/set-screen-power-mode.d.ts.map +1 -1
- package/esm/device-message/ack-clipboard.d.ts +9 -0
- package/esm/device-message/ack-clipboard.d.ts.map +1 -0
- package/esm/device-message/ack-clipboard.js +6 -0
- package/esm/device-message/ack-clipboard.js.map +1 -0
- package/esm/device-message/clipboard.d.ts +3 -3
- package/esm/device-message/clipboard.d.ts.map +1 -1
- package/esm/device-message/clipboard.js +4 -4
- package/esm/device-message/clipboard.js.map +1 -1
- package/esm/device-message/index.d.ts +4 -3
- package/esm/device-message/index.d.ts.map +1 -1
- package/esm/device-message/index.js +4 -3
- package/esm/device-message/index.js.map +1 -1
- package/esm/device-message/stream.d.ts +4 -3
- package/esm/device-message/stream.d.ts.map +1 -1
- package/esm/device-message/stream.js +8 -4
- package/esm/device-message/stream.js.map +1 -1
- package/esm/options/1_16/codec-options.d.ts +3 -2
- package/esm/options/1_16/codec-options.d.ts.map +1 -1
- package/esm/options/1_16/codec-options.js +6 -7
- package/esm/options/1_16/codec-options.js.map +1 -1
- package/esm/options/1_16/h264-configuration.d.ts +49 -0
- package/esm/options/1_16/h264-configuration.d.ts.map +1 -0
- package/esm/options/1_16/h264-configuration.js +414 -0
- package/esm/options/1_16/h264-configuration.js.map +1 -0
- package/esm/options/1_16/index.d.ts +4 -3
- package/esm/options/1_16/index.d.ts.map +1 -1
- package/esm/options/1_16/index.js +4 -3
- package/esm/options/1_16/index.js.map +1 -1
- package/esm/options/1_16/options.d.ts +17 -20
- package/esm/options/1_16/options.d.ts.map +1 -1
- package/esm/options/1_16/options.js +51 -49
- package/esm/options/1_16/options.js.map +1 -1
- package/esm/options/1_16/scroll.d.ts +27 -0
- package/esm/options/1_16/scroll.d.ts.map +1 -0
- package/esm/options/1_16/scroll.js +56 -0
- package/esm/options/1_16/scroll.js.map +1 -0
- package/esm/options/1_16/sps.d.ts +1 -1
- package/esm/options/1_16/sps.d.ts.map +1 -1
- package/esm/options/1_16/sps.js +25 -17
- package/esm/options/1_16/sps.js.map +1 -1
- package/esm/options/1_18.d.ts +6 -6
- package/esm/options/1_18.d.ts.map +1 -1
- package/esm/options/1_18.js +5 -5
- package/esm/options/1_18.js.map +1 -1
- package/esm/options/1_21.d.ts +12 -1
- package/esm/options/1_21.d.ts.map +1 -1
- package/esm/options/1_21.js +14 -3
- package/esm/options/1_21.js.map +1 -1
- package/esm/options/1_22/index.d.ts +3 -0
- package/esm/options/1_22/index.d.ts.map +1 -0
- package/esm/options/1_22/index.js +3 -0
- package/esm/options/1_22/index.js.map +1 -0
- package/esm/options/{1_22.d.ts → 1_22/options.d.ts} +4 -15
- package/esm/options/1_22/options.d.ts.map +1 -0
- package/esm/options/{1_22.js → 1_22/options.js} +5 -9
- package/esm/options/1_22/options.js.map +1 -0
- package/esm/options/1_22/scroll.d.ts +17 -0
- package/esm/options/1_22/scroll.d.ts.map +1 -0
- package/esm/options/1_22/scroll.js +15 -0
- package/esm/options/1_22/scroll.js.map +1 -0
- package/esm/options/1_23.d.ts +3 -3
- package/esm/options/1_23.d.ts.map +1 -1
- package/esm/options/1_23.js +7 -6
- package/esm/options/1_23.js.map +1 -1
- package/esm/options/1_25/index.d.ts +3 -0
- package/esm/options/1_25/index.d.ts.map +1 -0
- package/esm/options/1_25/index.js +3 -0
- package/esm/options/1_25/index.js.map +1 -0
- package/esm/options/1_25/options.d.ts +6 -0
- package/esm/options/1_25/options.d.ts.map +1 -0
- package/esm/options/1_25/options.js +8 -0
- package/esm/options/1_25/options.js.map +1 -0
- package/esm/options/1_25/scroll.d.ts +19 -0
- package/esm/options/1_25/scroll.d.ts.map +1 -0
- package/esm/options/1_25/scroll.js +33 -0
- package/esm/options/1_25/scroll.js.map +1 -0
- package/esm/options/index.d.ts +5 -4
- package/esm/options/index.d.ts.map +1 -1
- package/esm/options/index.js +5 -4
- package/esm/options/index.js.map +1 -1
- package/esm/options/types.d.ts +14 -12
- package/esm/options/types.d.ts.map +1 -1
- package/esm/options/types.js +6 -4
- package/esm/options/types.js.map +1 -1
- package/package.json +19 -12
- package/scripts/fetch-server.cjs +19 -9
- package/src/adb/client.ts +142 -89
- package/src/adb/connection.ts +77 -30
- package/src/adb/options/1_16.ts +13 -6
- package/src/adb/options/1_22.ts +12 -6
- package/src/adb/options/types.ts +34 -14
- package/src/control/back-or-screen-on.ts +4 -0
- package/src/control/hover-helper.ts +56 -0
- package/src/control/index.ts +11 -7
- package/src/control/inject-keycode.ts +23 -10
- package/src/control/inject-scroll.ts +4 -0
- package/src/control/inject-touch.ts +58 -14
- package/src/control/serializer.ts +106 -41
- package/src/control/set-clipboard.ts +4 -0
- package/src/device-message/ack-clipboard.ts +10 -0
- package/src/device-message/clipboard.ts +8 -8
- package/src/device-message/index.ts +4 -3
- package/src/device-message/stream.ts +17 -7
- package/src/options/1_16/codec-options.ts +17 -10
- package/src/options/1_16/h264-configuration.ts +485 -0
- package/src/options/1_16/index.ts +4 -3
- package/src/options/1_16/options.ts +175 -130
- package/src/options/1_16/scroll.ts +76 -0
- package/src/options/1_18.ts +22 -12
- package/src/options/1_21.ts +31 -13
- package/src/options/1_22/index.ts +2 -0
- package/src/options/{1_22.ts → 1_22/options.ts} +8 -17
- package/src/options/1_22/scroll.ts +26 -0
- package/src/options/1_23.ts +32 -20
- package/src/options/1_25/index.ts +2 -0
- package/src/options/1_25/options.ts +12 -0
- package/src/options/1_25/scroll.ts +52 -0
- package/src/options/index.ts +5 -4
- package/src/options/types.ts +34 -17
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/decoder/index.d.ts +0 -28
- package/esm/decoder/index.d.ts.map +0 -1
- package/esm/decoder/index.js +0 -2
- package/esm/decoder/index.js.map +0 -1
- package/esm/decoder/tinyh264/index.d.ts +0 -20
- package/esm/decoder/tinyh264/index.d.ts.map +0 -1
- package/esm/decoder/tinyh264/index.js +0 -86
- package/esm/decoder/tinyh264/index.js.map +0 -1
- package/esm/decoder/tinyh264/worker.d.ts +0 -2
- package/esm/decoder/tinyh264/worker.d.ts.map +0 -1
- package/esm/decoder/tinyh264/worker.js +0 -3
- package/esm/decoder/tinyh264/worker.js.map +0 -1
- package/esm/decoder/tinyh264/wrapper.d.ts +0 -21
- package/esm/decoder/tinyh264/wrapper.d.ts.map +0 -1
- package/esm/decoder/tinyh264/wrapper.js +0 -74
- package/esm/decoder/tinyh264/wrapper.js.map +0 -1
- package/esm/decoder/types.d.ts +0 -2
- package/esm/decoder/types.d.ts.map +0 -1
- package/esm/decoder/types.js +0 -2
- package/esm/decoder/types.js.map +0 -1
- package/esm/decoder/web-codecs/index.d.ts +0 -22
- package/esm/decoder/web-codecs/index.d.ts.map +0 -1
- package/esm/decoder/web-codecs/index.js +0 -81
- package/esm/decoder/web-codecs/index.js.map +0 -1
- package/esm/options/1_22.d.ts.map +0 -1
- package/esm/options/1_22.js.map +0 -1
- package/src/options/1_16/sps.ts +0 -300
- package/tsconfig.test.tsbuildinfo +0 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AndroidMotionEventAction,
|
|
3
|
+
type ScrcpyInjectTouchControlMessage,
|
|
4
|
+
} from "./inject-touch.js";
|
|
5
|
+
import { ScrcpyControlMessageType } from "./type.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* On both Android and Windows, while both mouse and touch are supported input devices,
|
|
9
|
+
* only one of them can be active at a time. Touch the screen with a finger will deactivate mouse,
|
|
10
|
+
* and move the mouse will deactivate touch.
|
|
11
|
+
*
|
|
12
|
+
* On Android, this is achieved by dispatching a `MotionEvent.ACTION_UP` event for the previous input type.
|
|
13
|
+
* But on Chrome, there is no such event, causing both mouse and touch to be active at the same time.
|
|
14
|
+
* This can cause the new input to appear as "ignored".
|
|
15
|
+
*
|
|
16
|
+
* This helper class synthesis `ACTION_UP` events when a different pointer type appears,
|
|
17
|
+
* so Scrcpy server can remove the previously hovering pointer.
|
|
18
|
+
*/
|
|
19
|
+
export class ScrcpyHoverHelper {
|
|
20
|
+
// AFAIK, only mouse and pen can have hover state
|
|
21
|
+
// and you can't have two mouses or pens.
|
|
22
|
+
// So remember the last hovering pointer is enough.
|
|
23
|
+
private lastHoverMessage: ScrcpyInjectTouchControlMessage | undefined;
|
|
24
|
+
|
|
25
|
+
public process(
|
|
26
|
+
message: Omit<ScrcpyInjectTouchControlMessage, "type">
|
|
27
|
+
): ScrcpyInjectTouchControlMessage[] {
|
|
28
|
+
const result: ScrcpyInjectTouchControlMessage[] = [];
|
|
29
|
+
|
|
30
|
+
// A different pointer appeared,
|
|
31
|
+
// Cancel previously hovering pointer so Scrcpy server can free up the pointer ID.
|
|
32
|
+
if (
|
|
33
|
+
this.lastHoverMessage &&
|
|
34
|
+
this.lastHoverMessage.pointerId !== message.pointerId
|
|
35
|
+
) {
|
|
36
|
+
// TODO: Inject MotionEvent.ACTION_HOVER_EXIT
|
|
37
|
+
// From testing, it seems no App cares about this event.
|
|
38
|
+
result.push({
|
|
39
|
+
...this.lastHoverMessage,
|
|
40
|
+
action: AndroidMotionEventAction.Up,
|
|
41
|
+
});
|
|
42
|
+
this.lastHoverMessage = undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (message.action === AndroidMotionEventAction.HoverMove) {
|
|
46
|
+
// TODO: Inject MotionEvent.ACTION_HOVER_ENTER
|
|
47
|
+
this.lastHoverMessage = message as ScrcpyInjectTouchControlMessage;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
(message as ScrcpyInjectTouchControlMessage).type =
|
|
51
|
+
ScrcpyControlMessageType.InjectTouch;
|
|
52
|
+
result.push(message as ScrcpyInjectTouchControlMessage);
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/control/index.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
1
|
+
export * from "./back-or-screen-on.js";
|
|
2
|
+
export * from "./hover-helper.js";
|
|
3
|
+
export * from "./inject-keycode.js";
|
|
4
|
+
export * from "./inject-scroll.js";
|
|
5
|
+
export * from "./inject-text.js";
|
|
6
|
+
export * from "./inject-touch.js";
|
|
7
|
+
export * from "./rotate-device.js";
|
|
8
|
+
export * from "./serializer.js";
|
|
9
|
+
export * from "./set-clipboard.js";
|
|
10
|
+
export * from "./set-screen-power-mode.js";
|
|
11
|
+
export * from "./type.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import Struct, { placeholder } from
|
|
1
|
+
import Struct, { placeholder } from "@yume-chan/struct";
|
|
2
2
|
|
|
3
|
-
import { ScrcpyControlMessageType } from
|
|
3
|
+
import { ScrcpyControlMessageType } from "./type.js";
|
|
4
4
|
|
|
5
5
|
export enum AndroidKeyEventAction {
|
|
6
6
|
Down = 0,
|
|
@@ -11,8 +11,15 @@ export enum AndroidKeyEventAction {
|
|
|
11
11
|
export enum AndroidKeyCode {
|
|
12
12
|
Home = 3,
|
|
13
13
|
Back = 4,
|
|
14
|
+
|
|
15
|
+
DPadUp = 19,
|
|
16
|
+
DPadDown,
|
|
17
|
+
DPadLeft,
|
|
18
|
+
DPadRight,
|
|
19
|
+
|
|
14
20
|
VolumeUp = 24,
|
|
15
21
|
VolumeDown,
|
|
22
|
+
|
|
16
23
|
A = 29,
|
|
17
24
|
B,
|
|
18
25
|
C,
|
|
@@ -39,21 +46,27 @@ export enum AndroidKeyCode {
|
|
|
39
46
|
X,
|
|
40
47
|
Y,
|
|
41
48
|
Z,
|
|
49
|
+
|
|
42
50
|
Tab = 61,
|
|
43
51
|
Space,
|
|
44
52
|
Enter = 66,
|
|
45
53
|
Delete,
|
|
54
|
+
Escape = 111,
|
|
55
|
+
ForwardDelete,
|
|
56
|
+
|
|
57
|
+
MoveHome = 122,
|
|
58
|
+
MoveEnd = 123,
|
|
59
|
+
|
|
46
60
|
VolumeMute = 164,
|
|
47
61
|
AppSwitch = 187,
|
|
48
62
|
}
|
|
49
63
|
|
|
50
|
-
export const ScrcpyInjectKeyCodeControlMessage =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.uint32('metaState');
|
|
64
|
+
export const ScrcpyInjectKeyCodeControlMessage = new Struct()
|
|
65
|
+
.uint8("type", ScrcpyControlMessageType.InjectKeyCode as const)
|
|
66
|
+
.uint8("action", placeholder<AndroidKeyEventAction>())
|
|
67
|
+
.uint32("keyCode")
|
|
68
|
+
.uint32("repeat")
|
|
69
|
+
.uint32("metaState");
|
|
57
70
|
|
|
58
71
|
export type ScrcpyInjectKeyCodeControlMessage =
|
|
59
|
-
typeof ScrcpyInjectKeyCodeControlMessage[
|
|
72
|
+
typeof ScrcpyInjectKeyCodeControlMessage["TInit"];
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import Struct, {
|
|
2
|
-
|
|
1
|
+
import Struct, {
|
|
2
|
+
NumberFieldDefinition,
|
|
3
|
+
NumberFieldType,
|
|
4
|
+
placeholder,
|
|
5
|
+
} from "@yume-chan/struct";
|
|
6
|
+
|
|
7
|
+
import { ScrcpyControlMessageType } from "./type.js";
|
|
3
8
|
|
|
4
9
|
// https://developer.android.com/reference/android/view/MotionEvent#constants_1
|
|
5
10
|
export enum AndroidMotionEventAction {
|
|
@@ -18,17 +23,56 @@ export enum AndroidMotionEventAction {
|
|
|
18
23
|
ButtonRelease,
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
27
|
+
export namespace ScrcpyPointerId {
|
|
28
|
+
export const Mouse = BigInt(-1);
|
|
29
|
+
export const Finger = BigInt(-2);
|
|
30
|
+
export const VirtualMouse = BigInt(-3);
|
|
31
|
+
export const VirtualFinger = BigInt(-4);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function clamp(value: number, min: number, max: number): number {
|
|
35
|
+
if (value < min) {
|
|
36
|
+
return min;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (value > max) {
|
|
40
|
+
return max;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
|
|
47
|
+
size: 2,
|
|
48
|
+
signed: false,
|
|
49
|
+
deserialize(array, littleEndian) {
|
|
50
|
+
const value = NumberFieldType.Uint16.deserialize(array, littleEndian);
|
|
51
|
+
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/server/src/main/java/com/genymobile/scrcpy/Binary.java#L22
|
|
52
|
+
return value === 0xffff ? 1 : value / 0x10000;
|
|
53
|
+
},
|
|
54
|
+
serialize(dataView, offset, value, littleEndian) {
|
|
55
|
+
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L51
|
|
56
|
+
value = clamp(value, -1, 1);
|
|
57
|
+
value = value === 1 ? 0xffff : value * 0x10000;
|
|
58
|
+
NumberFieldType.Uint16.serialize(dataView, offset, value, littleEndian);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const ScrcpyFloatToUint16FieldDefinition = new NumberFieldDefinition(
|
|
63
|
+
ScrcpyFloatToUint16NumberType
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export const ScrcpyInjectTouchControlMessage = new Struct()
|
|
67
|
+
.uint8("type", ScrcpyControlMessageType.InjectTouch as const)
|
|
68
|
+
.uint8("action", placeholder<AndroidMotionEventAction>())
|
|
69
|
+
.uint64("pointerId")
|
|
70
|
+
.uint32("pointerX")
|
|
71
|
+
.uint32("pointerY")
|
|
72
|
+
.uint16("screenWidth")
|
|
73
|
+
.uint16("screenHeight")
|
|
74
|
+
.field("pressure", ScrcpyFloatToUint16FieldDefinition)
|
|
75
|
+
.uint32("buttons");
|
|
32
76
|
|
|
33
77
|
export type ScrcpyInjectTouchControlMessage =
|
|
34
|
-
typeof ScrcpyInjectTouchControlMessage[
|
|
78
|
+
typeof ScrcpyInjectTouchControlMessage["TInit"];
|
|
@@ -1,65 +1,122 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type WritableStream,
|
|
3
|
+
type WritableStreamDefaultWriter,
|
|
4
|
+
} from "@yume-chan/stream-extra";
|
|
2
5
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
|
|
6
|
+
import {
|
|
7
|
+
type ScrcpyOptions,
|
|
8
|
+
type ScrcpyScrollController,
|
|
9
|
+
} from "../options/index.js";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
ScrcpyInjectKeyCodeControlMessage,
|
|
13
|
+
type AndroidKeyEventAction,
|
|
14
|
+
} from "./inject-keycode.js";
|
|
15
|
+
import { type ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
|
|
16
|
+
import { ScrcpyInjectTextControlMessage } from "./inject-text.js";
|
|
17
|
+
import { ScrcpyInjectTouchControlMessage } from "./inject-touch.js";
|
|
18
|
+
import { ScrcpyRotateDeviceControlMessage } from "./rotate-device.js";
|
|
19
|
+
import {
|
|
20
|
+
ScrcpySetScreenPowerModeControlMessage,
|
|
21
|
+
type AndroidScreenPowerMode,
|
|
22
|
+
} from "./set-screen-power-mode.js";
|
|
23
|
+
import { ScrcpyControlMessageType } from "./type.js";
|
|
10
24
|
|
|
11
25
|
export class ScrcpyControlMessageSerializer {
|
|
12
|
-
private options: ScrcpyOptions<
|
|
26
|
+
private options: ScrcpyOptions<object>;
|
|
13
27
|
/** Control message type values for current version of server */
|
|
14
28
|
private types: ScrcpyControlMessageType[];
|
|
15
29
|
private writer: WritableStreamDefaultWriter<Uint8Array>;
|
|
30
|
+
private scrollController: ScrcpyScrollController;
|
|
31
|
+
|
|
32
|
+
public constructor(
|
|
33
|
+
stream: WritableStream<Uint8Array>,
|
|
34
|
+
options: ScrcpyOptions<object>
|
|
35
|
+
) {
|
|
36
|
+
this.writer = stream.getWriter();
|
|
16
37
|
|
|
17
|
-
public constructor(stream: WritableStream<Uint8Array>, options: ScrcpyOptions<any>) {
|
|
18
38
|
this.options = options;
|
|
19
39
|
this.types = options.getControlMessageTypes();
|
|
20
|
-
this.
|
|
40
|
+
this.scrollController = options.getScrollController();
|
|
21
41
|
}
|
|
22
42
|
|
|
23
|
-
public
|
|
43
|
+
public getActualMessageType(type: ScrcpyControlMessageType): number {
|
|
24
44
|
const value = this.types.indexOf(type);
|
|
25
45
|
if (value === -1) {
|
|
26
|
-
throw new Error(
|
|
46
|
+
throw new Error("Not supported");
|
|
27
47
|
}
|
|
28
48
|
return value;
|
|
29
49
|
}
|
|
30
50
|
|
|
31
|
-
public
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
public addMessageType<T extends { type: ScrcpyControlMessageType }>(
|
|
52
|
+
message: Omit<T, "type">,
|
|
53
|
+
type: T["type"]
|
|
54
|
+
): T {
|
|
55
|
+
(message as T).type = this.getActualMessageType(type);
|
|
56
|
+
return message as T;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public injectKeyCode(
|
|
60
|
+
message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">
|
|
61
|
+
) {
|
|
62
|
+
return this.writer.write(
|
|
63
|
+
ScrcpyInjectKeyCodeControlMessage.serialize(
|
|
64
|
+
this.addMessageType(
|
|
65
|
+
message,
|
|
66
|
+
ScrcpyControlMessageType.InjectKeyCode
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
);
|
|
36
70
|
}
|
|
37
71
|
|
|
38
72
|
public injectText(text: string) {
|
|
39
|
-
return this.writer.write(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
73
|
+
return this.writer.write(
|
|
74
|
+
ScrcpyInjectTextControlMessage.serialize({
|
|
75
|
+
text,
|
|
76
|
+
type: this.getActualMessageType(
|
|
77
|
+
ScrcpyControlMessageType.InjectText
|
|
78
|
+
),
|
|
79
|
+
})
|
|
80
|
+
);
|
|
43
81
|
}
|
|
44
82
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
83
|
+
/**
|
|
84
|
+
* `pressure` is a float value between 0 and 1.
|
|
85
|
+
*/
|
|
86
|
+
public injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
|
|
87
|
+
return this.writer.write(
|
|
88
|
+
ScrcpyInjectTouchControlMessage.serialize(
|
|
89
|
+
this.addMessageType(
|
|
90
|
+
message,
|
|
91
|
+
ScrcpyControlMessageType.InjectTouch
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
);
|
|
50
95
|
}
|
|
51
96
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
97
|
+
/**
|
|
98
|
+
* `scrollX` and `scrollY` are float values between 0 and 1.
|
|
99
|
+
*/
|
|
100
|
+
public injectScroll(
|
|
101
|
+
message: Omit<ScrcpyInjectScrollControlMessage, "type">
|
|
102
|
+
) {
|
|
103
|
+
const data = this.scrollController.serializeScrollMessage(
|
|
104
|
+
this.addMessageType(message, ScrcpyControlMessageType.InjectScroll)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (!data) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return this.writer.write(data);
|
|
57
112
|
}
|
|
58
113
|
|
|
59
114
|
public async backOrScreenOn(action: AndroidKeyEventAction) {
|
|
60
115
|
const buffer = this.options.serializeBackOrScreenOnControlMessage({
|
|
61
116
|
action,
|
|
62
|
-
type: this.
|
|
117
|
+
type: this.getActualMessageType(
|
|
118
|
+
ScrcpyControlMessageType.BackOrScreenOn
|
|
119
|
+
),
|
|
63
120
|
});
|
|
64
121
|
|
|
65
122
|
if (buffer) {
|
|
@@ -68,19 +125,27 @@ export class ScrcpyControlMessageSerializer {
|
|
|
68
125
|
}
|
|
69
126
|
|
|
70
127
|
public setScreenPowerMode(mode: AndroidScreenPowerMode) {
|
|
71
|
-
return this.writer.write(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
128
|
+
return this.writer.write(
|
|
129
|
+
ScrcpySetScreenPowerModeControlMessage.serialize({
|
|
130
|
+
mode,
|
|
131
|
+
type: this.getActualMessageType(
|
|
132
|
+
ScrcpyControlMessageType.SetScreenPowerMode
|
|
133
|
+
),
|
|
134
|
+
})
|
|
135
|
+
);
|
|
75
136
|
}
|
|
76
137
|
|
|
77
138
|
public rotateDevice() {
|
|
78
|
-
return this.writer.write(
|
|
79
|
-
|
|
80
|
-
|
|
139
|
+
return this.writer.write(
|
|
140
|
+
ScrcpyRotateDeviceControlMessage.serialize({
|
|
141
|
+
type: this.getActualMessageType(
|
|
142
|
+
ScrcpyControlMessageType.RotateDevice
|
|
143
|
+
),
|
|
144
|
+
})
|
|
145
|
+
);
|
|
81
146
|
}
|
|
82
147
|
|
|
83
148
|
public close() {
|
|
84
149
|
return this.writer.close();
|
|
85
150
|
}
|
|
86
|
-
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Struct from "@yume-chan/struct";
|
|
2
|
+
|
|
3
|
+
import { ScrcpyDeviceMessageType } from "./type.js";
|
|
4
|
+
|
|
5
|
+
export const ScrcpyAckClipboardDeviceMessage = new Struct()
|
|
6
|
+
.uint64("sequence")
|
|
7
|
+
.extra({ type: ScrcpyDeviceMessageType.AckClipboard as const });
|
|
8
|
+
|
|
9
|
+
export type ScrcpyAckClipboardDeviceMessage =
|
|
10
|
+
typeof ScrcpyAckClipboardDeviceMessage["TDeserializeResult"];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import Struct from
|
|
2
|
-
import { ScrcpyDeviceMessageType } from './type.js';
|
|
1
|
+
import Struct from "@yume-chan/struct";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import { ScrcpyDeviceMessageType } from "./type.js";
|
|
4
|
+
|
|
5
|
+
export const ScrcpyClipboardDeviceMessage = new Struct()
|
|
6
|
+
.uint32("length")
|
|
7
|
+
.string("content", { lengthField: "length" })
|
|
8
|
+
.extra({ type: ScrcpyDeviceMessageType.Clipboard as const });
|
|
9
9
|
|
|
10
10
|
export type ScrcpyClipboardDeviceMessage =
|
|
11
|
-
typeof ScrcpyClipboardDeviceMessage[
|
|
11
|
+
typeof ScrcpyClipboardDeviceMessage["TDeserializeResult"];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
1
|
+
export * from "./ack-clipboard.js";
|
|
2
|
+
export * from "./clipboard.js";
|
|
3
|
+
export * from "./stream.js";
|
|
4
|
+
export * from "./type.js";
|
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
import { BufferedTransformStream } from
|
|
2
|
-
|
|
1
|
+
import { BufferedTransformStream } from "@yume-chan/stream-extra";
|
|
2
|
+
|
|
3
|
+
import { ScrcpyAckClipboardDeviceMessage } from "./ack-clipboard.js";
|
|
4
|
+
import { ScrcpyClipboardDeviceMessage } from "./clipboard.js";
|
|
5
|
+
import { ScrcpyDeviceMessageType } from "./type.js";
|
|
3
6
|
|
|
4
7
|
export type ScrcpyDeviceMessage =
|
|
5
|
-
| ScrcpyClipboardDeviceMessage
|
|
8
|
+
| ScrcpyClipboardDeviceMessage
|
|
9
|
+
| ScrcpyAckClipboardDeviceMessage;
|
|
6
10
|
|
|
7
11
|
export class ScrcpyDeviceMessageDeserializeStream extends BufferedTransformStream<ScrcpyDeviceMessage> {
|
|
8
12
|
constructor() {
|
|
9
13
|
super(async (stream) => {
|
|
10
14
|
const type = await stream.read(1);
|
|
11
15
|
switch (type[0]) {
|
|
12
|
-
case
|
|
13
|
-
return await ScrcpyClipboardDeviceMessage.deserialize(
|
|
16
|
+
case ScrcpyDeviceMessageType.Clipboard:
|
|
17
|
+
return await ScrcpyClipboardDeviceMessage.deserialize(
|
|
18
|
+
stream
|
|
19
|
+
);
|
|
20
|
+
case ScrcpyDeviceMessageType.AckClipboard:
|
|
21
|
+
return await ScrcpyAckClipboardDeviceMessage.deserialize(
|
|
22
|
+
stream
|
|
23
|
+
);
|
|
14
24
|
default:
|
|
15
|
-
throw new Error(
|
|
25
|
+
throw new Error("unknown control message type");
|
|
16
26
|
}
|
|
17
|
-
})
|
|
27
|
+
});
|
|
18
28
|
}
|
|
19
29
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type AndroidCodecLevel,
|
|
3
|
+
type AndroidCodecProfile,
|
|
4
|
+
} from "../../codec.js";
|
|
5
|
+
import { type ScrcpyOptionValue } from "../types.js";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* If the option you need is not in this type,
|
|
@@ -10,17 +13,20 @@ export interface CodecOptionsInit {
|
|
|
10
13
|
level: AndroidCodecLevel;
|
|
11
14
|
|
|
12
15
|
iFrameInterval: number;
|
|
16
|
+
maxBframes: number;
|
|
13
17
|
repeatPreviousFrameAfter: number;
|
|
14
18
|
maxPtsGapToEncoder: number;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
function toDashCase(input: string) {
|
|
18
|
-
return input.replace(/([A-Z])/g,
|
|
22
|
+
return input.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
const CODEC_OPTION_TYPES: Partial<
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const CODEC_OPTION_TYPES: Partial<
|
|
26
|
+
Record<keyof CodecOptionsInit, "long" | "float" | "string">
|
|
27
|
+
> = {
|
|
28
|
+
repeatPreviousFrameAfter: "long",
|
|
29
|
+
maxPtsGapToEncoder: "long",
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
export class CodecOptions implements ScrcpyOptionValue {
|
|
@@ -31,8 +37,9 @@ export class CodecOptions implements ScrcpyOptionValue {
|
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
public toOptionValue(): string | undefined {
|
|
34
|
-
const entries = Object.entries(this.value)
|
|
35
|
-
|
|
40
|
+
const entries = Object.entries(this.value).filter(
|
|
41
|
+
([, value]) => value !== undefined
|
|
42
|
+
);
|
|
36
43
|
|
|
37
44
|
if (entries.length === 0) {
|
|
38
45
|
return undefined;
|
|
@@ -41,8 +48,8 @@ export class CodecOptions implements ScrcpyOptionValue {
|
|
|
41
48
|
return entries
|
|
42
49
|
.map(([key, value]) => {
|
|
43
50
|
const type = CODEC_OPTION_TYPES[key as keyof CodecOptionsInit];
|
|
44
|
-
return `${toDashCase(key)}${type ? `:${type}` :
|
|
51
|
+
return `${toDashCase(key)}${type ? `:${type}` : ""}=${value}`;
|
|
45
52
|
})
|
|
46
|
-
.join(
|
|
53
|
+
.join(",");
|
|
47
54
|
}
|
|
48
55
|
}
|