@yume-chan/scrcpy 0.0.14 → 0.0.15
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 +15 -0
- package/CHANGELOG.md +9 -1
- package/esm/client.d.ts +14 -2
- package/esm/client.d.ts.map +1 -1
- package/esm/client.js +275 -143
- package/esm/client.js.map +1 -1
- package/esm/connection.js +74 -85
- package/esm/connection.js.map +1 -1
- package/esm/decoder/tinyh264/index.js +48 -48
- package/esm/decoder/tinyh264/index.js.map +1 -1
- package/esm/decoder/tinyh264/wrapper.js +3 -2
- package/esm/decoder/tinyh264/wrapper.js.map +1 -1
- package/esm/decoder/web-codecs/index.js +26 -21
- package/esm/decoder/web-codecs/index.js.map +1 -1
- package/esm/message.d.ts +12 -8
- package/esm/message.d.ts.map +1 -1
- package/esm/message.js +13 -8
- package/esm/message.js.map +1 -1
- package/esm/options/1_16/index.d.ts +5 -4
- package/esm/options/1_16/index.d.ts.map +1 -1
- package/esm/options/1_16/index.js +33 -17
- package/esm/options/1_16/index.js.map +1 -1
- package/esm/options/1_16/sps.js +3 -2
- package/esm/options/1_16/sps.js.map +1 -1
- package/esm/options/1_18.d.ts +3 -2
- package/esm/options/1_18.d.ts.map +1 -1
- package/esm/options/1_18.js +24 -1
- package/esm/options/1_18.js.map +1 -1
- package/esm/options/1_21.js +4 -1
- package/esm/options/1_21.js.map +1 -1
- package/esm/options/1_22.d.ts +3 -3
- package/esm/options/1_22.d.ts.map +1 -1
- package/esm/options/1_22.js +9 -6
- package/esm/options/1_22.js.map +1 -1
- package/esm/options/1_23.js +4 -1
- package/esm/options/1_23.js.map +1 -1
- package/esm/options/1_24.js +4 -1
- package/esm/options/1_24.js.map +1 -1
- package/esm/options/common.d.ts +2 -0
- package/esm/options/common.d.ts.map +1 -1
- package/esm/options/common.js.map +1 -1
- package/esm/push-server.js +5 -10
- package/esm/push-server.js.map +1 -1
- package/package.json +4 -4
- package/src/client.ts +181 -21
- package/src/connection.ts +1 -1
- package/src/message.ts +10 -3
- package/src/options/1_16/index.ts +25 -10
- package/src/options/1_18.ts +21 -1
- package/src/options/1_22.ts +6 -8
- package/src/options/common.ts +3 -0
package/src/client.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AdbBufferedStream, AdbSubprocessNoneProtocol, DecodeUtf8Stream, InspectStream, TransformStream, WritableStream, type Adb, type AdbSocket, type AdbSubprocessProtocol, type
|
|
1
|
+
import { AbortController, AdbBufferedStream, AdbSubprocessNoneProtocol, DecodeUtf8Stream, InspectStream, ReadableStream, TransformStream, WritableStream, type Adb, type AdbSocket, type AdbSubprocessProtocol, type WritableStreamDefaultWriter } from '@yume-chan/adb';
|
|
2
2
|
import { EventEmitter } from '@yume-chan/event';
|
|
3
3
|
import Struct from '@yume-chan/struct';
|
|
4
|
-
import { AndroidMotionEventAction, ScrcpyControlMessageType, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, type AndroidKeyEventAction } from './message.js';
|
|
4
|
+
import { AndroidMotionEventAction, ScrcpyControlMessageType, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, ScrcpySimpleControlMessage, type AndroidKeyEventAction } from './message.js';
|
|
5
5
|
import type { ScrcpyInjectScrollControlMessage1_22, ScrcpyOptions, VideoStreamPacket } from "./options/index.js";
|
|
6
6
|
|
|
7
7
|
function* splitLines(text: string): Generator<string, void, void> {
|
|
@@ -20,12 +20,87 @@ function* splitLines(text: string): Generator<string, void, void> {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
class SplitLinesStream extends TransformStream<string, string>{
|
|
24
|
+
constructor() {
|
|
25
|
+
super({
|
|
26
|
+
transform(chunk, controller) {
|
|
27
|
+
for (const line of splitLines(chunk)) {
|
|
28
|
+
if (line === '') {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
controller.enqueue(line);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class ArrayToStream<T> extends ReadableStream<T>{
|
|
39
|
+
private array!: T[];
|
|
40
|
+
private index = 0;
|
|
41
|
+
|
|
42
|
+
constructor(array: T[]) {
|
|
43
|
+
super({
|
|
44
|
+
start: async () => {
|
|
45
|
+
await Promise.resolve();
|
|
46
|
+
this.array = array;
|
|
47
|
+
},
|
|
48
|
+
pull: (controller) => {
|
|
49
|
+
if (this.index < this.array.length) {
|
|
50
|
+
controller.enqueue(this.array[this.index]!);
|
|
51
|
+
this.index += 1;
|
|
52
|
+
} else {
|
|
53
|
+
controller.close();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class ConcatStream<T> extends ReadableStream<T>{
|
|
61
|
+
private streams!: ReadableStream<T>[];
|
|
62
|
+
private index = 0;
|
|
63
|
+
private reader!: ReadableStreamDefaultReader<T>;
|
|
64
|
+
|
|
65
|
+
constructor(...streams: ReadableStream<T>[]) {
|
|
66
|
+
super({
|
|
67
|
+
start: async (controller) => {
|
|
68
|
+
await Promise.resolve();
|
|
69
|
+
|
|
70
|
+
this.streams = streams;
|
|
71
|
+
this.advance(controller);
|
|
72
|
+
},
|
|
73
|
+
pull: async (controller) => {
|
|
74
|
+
const result = await this.reader.read();
|
|
75
|
+
if (!result.done) {
|
|
76
|
+
controller.enqueue(result.value);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.advance(controller);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private advance(controller: ReadableStreamDefaultController<T>) {
|
|
85
|
+
if (this.index < this.streams.length) {
|
|
86
|
+
this.reader = this.streams[this.index]!.getReader();
|
|
87
|
+
this.index += 1;
|
|
88
|
+
} else {
|
|
89
|
+
controller.close();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
23
94
|
const ClipboardMessage =
|
|
24
95
|
new Struct()
|
|
25
96
|
.uint32('length')
|
|
26
97
|
.string('content', { lengthField: 'length' });
|
|
27
98
|
|
|
28
99
|
export class ScrcpyClient {
|
|
100
|
+
/**
|
|
101
|
+
* This method will modify the given `options`,
|
|
102
|
+
* so don't reuse it elsewhere.
|
|
103
|
+
*/
|
|
29
104
|
public static async getEncoders(
|
|
30
105
|
adb: Adb,
|
|
31
106
|
path: string,
|
|
@@ -37,6 +112,8 @@ export class ScrcpyClient {
|
|
|
37
112
|
options.value.encoderName = '_';
|
|
38
113
|
// Disable control for faster connection in 1.22+
|
|
39
114
|
options.value.control = false;
|
|
115
|
+
options.value.sendDeviceMeta = false;
|
|
116
|
+
options.value.sendDummyByte = false;
|
|
40
117
|
|
|
41
118
|
// Scrcpy server will open connections, before initializing encoder
|
|
42
119
|
// Thus although an invalid encoder name is given, the start process will success
|
|
@@ -56,6 +133,45 @@ export class ScrcpyClient {
|
|
|
56
133
|
return encoders;
|
|
57
134
|
}
|
|
58
135
|
|
|
136
|
+
/**
|
|
137
|
+
* This method will modify the given `options`,
|
|
138
|
+
* so don't reuse it elsewhere.
|
|
139
|
+
*/
|
|
140
|
+
public static async getDisplays(
|
|
141
|
+
adb: Adb,
|
|
142
|
+
path: string,
|
|
143
|
+
version: string,
|
|
144
|
+
options: ScrcpyOptions<any>
|
|
145
|
+
): Promise<number[]> {
|
|
146
|
+
// Similar to `getEncoders`, pass an invalid option and parse the output
|
|
147
|
+
options.value.displayId = -1;
|
|
148
|
+
|
|
149
|
+
options.value.control = false;
|
|
150
|
+
options.value.sendDeviceMeta = false;
|
|
151
|
+
options.value.sendDummyByte = false;
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
// Server will exit before opening connections when an invalid display id was given.
|
|
155
|
+
await ScrcpyClient.start(adb, path, version, options);
|
|
156
|
+
} catch (e) {
|
|
157
|
+
if (e instanceof Error) {
|
|
158
|
+
const output = (e as any).output as string[];
|
|
159
|
+
|
|
160
|
+
const displayIdRegex = /\s+scrcpy --display (\d+)/;
|
|
161
|
+
const displays: number[] = [];
|
|
162
|
+
for (const line of output) {
|
|
163
|
+
const match = line.match(displayIdRegex);
|
|
164
|
+
if (match) {
|
|
165
|
+
displays.push(Number.parseInt(match[1]!, 10));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return displays;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
throw new Error('failed to get displays');
|
|
173
|
+
}
|
|
174
|
+
|
|
59
175
|
public static async start(
|
|
60
176
|
adb: Adb,
|
|
61
177
|
path: string,
|
|
@@ -85,17 +201,50 @@ export class ScrcpyClient {
|
|
|
85
201
|
}
|
|
86
202
|
);
|
|
87
203
|
|
|
204
|
+
const stdout = process.stdout
|
|
205
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
206
|
+
.pipeThrough(new SplitLinesStream());
|
|
207
|
+
|
|
208
|
+
// Read stdout, otherwise `process.exit` won't resolve.
|
|
209
|
+
const output: string[] = [];
|
|
210
|
+
const abortController = new AbortController();
|
|
211
|
+
const pipe = stdout
|
|
212
|
+
.pipeTo(new WritableStream({
|
|
213
|
+
write(chunk) {
|
|
214
|
+
output.push(chunk);
|
|
215
|
+
}
|
|
216
|
+
}), {
|
|
217
|
+
signal: abortController.signal,
|
|
218
|
+
preventCancel: true,
|
|
219
|
+
})
|
|
220
|
+
.catch(() => { });
|
|
221
|
+
|
|
88
222
|
const result = await Promise.race([
|
|
89
223
|
process.exit,
|
|
90
224
|
connection.getStreams(),
|
|
91
225
|
]);
|
|
92
226
|
|
|
93
227
|
if (typeof result === 'number') {
|
|
94
|
-
|
|
228
|
+
const error = new Error('scrcpy server exited prematurely');
|
|
229
|
+
(error as any).output = output;
|
|
230
|
+
throw error;
|
|
95
231
|
}
|
|
96
232
|
|
|
233
|
+
abortController.abort();
|
|
234
|
+
await pipe;
|
|
235
|
+
|
|
97
236
|
const [videoStream, controlStream] = result;
|
|
98
|
-
return new ScrcpyClient(
|
|
237
|
+
return new ScrcpyClient(
|
|
238
|
+
adb,
|
|
239
|
+
options,
|
|
240
|
+
process,
|
|
241
|
+
new ConcatStream(
|
|
242
|
+
new ArrayToStream(output),
|
|
243
|
+
stdout,
|
|
244
|
+
),
|
|
245
|
+
videoStream,
|
|
246
|
+
controlStream
|
|
247
|
+
);
|
|
99
248
|
} catch (e) {
|
|
100
249
|
await process?.kill();
|
|
101
250
|
throw e;
|
|
@@ -135,6 +284,7 @@ export class ScrcpyClient {
|
|
|
135
284
|
adb: Adb,
|
|
136
285
|
options: ScrcpyOptions<any>,
|
|
137
286
|
process: AdbSubprocessProtocol,
|
|
287
|
+
stdout: ReadableStream<string>,
|
|
138
288
|
videoStream: AdbSocket,
|
|
139
289
|
controlStream: AdbSocket | undefined,
|
|
140
290
|
) {
|
|
@@ -142,18 +292,7 @@ export class ScrcpyClient {
|
|
|
142
292
|
this.options = options;
|
|
143
293
|
this.process = process;
|
|
144
294
|
|
|
145
|
-
this._stdout =
|
|
146
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
147
|
-
.pipeThrough(new TransformStream({
|
|
148
|
-
transform(chunk, controller) {
|
|
149
|
-
for (const line of splitLines(chunk)) {
|
|
150
|
-
if (line === '') {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
controller.enqueue(line);
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
}));
|
|
295
|
+
this._stdout = stdout;
|
|
157
296
|
|
|
158
297
|
this._videoStream = videoStream.readable
|
|
159
298
|
.pipeThrough(options.createVideoStreamTransformer())
|
|
@@ -195,12 +334,21 @@ export class ScrcpyClient {
|
|
|
195
334
|
return this._controlStreamWriter;
|
|
196
335
|
}
|
|
197
336
|
|
|
337
|
+
private getControlMessageTypeValue(type: ScrcpyControlMessageType) {
|
|
338
|
+
const list = this.options.getControlMessageTypes();
|
|
339
|
+
const index = list.indexOf(type);
|
|
340
|
+
if (index === -1) {
|
|
341
|
+
throw new Error('Not supported');
|
|
342
|
+
}
|
|
343
|
+
return index;
|
|
344
|
+
}
|
|
345
|
+
|
|
198
346
|
public async injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, 'type'>) {
|
|
199
347
|
const controlStream = this.checkControlStream('injectKeyCode');
|
|
200
348
|
|
|
201
349
|
await controlStream.write(ScrcpyInjectKeyCodeControlMessage.serialize({
|
|
202
350
|
...message,
|
|
203
|
-
type: ScrcpyControlMessageType.InjectKeycode,
|
|
351
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectKeycode),
|
|
204
352
|
}));
|
|
205
353
|
}
|
|
206
354
|
|
|
@@ -208,7 +356,7 @@ export class ScrcpyClient {
|
|
|
208
356
|
const controlStream = this.checkControlStream('injectText');
|
|
209
357
|
|
|
210
358
|
await controlStream.write(ScrcpyInjectTextControlMessage.serialize({
|
|
211
|
-
type: ScrcpyControlMessageType.InjectText,
|
|
359
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectText),
|
|
212
360
|
text,
|
|
213
361
|
}));
|
|
214
362
|
}
|
|
@@ -234,7 +382,7 @@ export class ScrcpyClient {
|
|
|
234
382
|
this.lastTouchMessage = now;
|
|
235
383
|
await controlStream.write(ScrcpyInjectTouchControlMessage.serialize({
|
|
236
384
|
...message,
|
|
237
|
-
type: ScrcpyControlMessageType.InjectTouch,
|
|
385
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectTouch),
|
|
238
386
|
screenWidth: this.screenWidth,
|
|
239
387
|
screenHeight: this.screenHeight,
|
|
240
388
|
}));
|
|
@@ -249,7 +397,7 @@ export class ScrcpyClient {
|
|
|
249
397
|
|
|
250
398
|
const buffer = this.options!.serializeInjectScrollControlMessage({
|
|
251
399
|
...message,
|
|
252
|
-
type: ScrcpyControlMessageType.InjectScroll,
|
|
400
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectScroll),
|
|
253
401
|
screenWidth: this.screenWidth,
|
|
254
402
|
screenHeight: this.screenHeight,
|
|
255
403
|
});
|
|
@@ -260,7 +408,7 @@ export class ScrcpyClient {
|
|
|
260
408
|
const controlStream = this.checkControlStream('pressBackOrTurnOnScreen');
|
|
261
409
|
|
|
262
410
|
const buffer = this.options!.serializeBackOrScreenOnControlMessage({
|
|
263
|
-
type: ScrcpyControlMessageType.BackOrScreenOn,
|
|
411
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.BackOrScreenOn),
|
|
264
412
|
action,
|
|
265
413
|
});
|
|
266
414
|
if (buffer) {
|
|
@@ -268,6 +416,18 @@ export class ScrcpyClient {
|
|
|
268
416
|
}
|
|
269
417
|
}
|
|
270
418
|
|
|
419
|
+
private async sendSimpleControlMessage(type: ScrcpyControlMessageType, name: string) {
|
|
420
|
+
const controlStream = this.checkControlStream(name);
|
|
421
|
+
const buffer = ScrcpySimpleControlMessage.serialize({
|
|
422
|
+
type: this.getControlMessageTypeValue(type),
|
|
423
|
+
});
|
|
424
|
+
await controlStream.write(buffer);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
public async rotateDevice() {
|
|
428
|
+
await this.sendSimpleControlMessage(ScrcpyControlMessageType.RotateDevice, 'rotateDevice');
|
|
429
|
+
}
|
|
430
|
+
|
|
271
431
|
public async close() {
|
|
272
432
|
// No need to close streams. Kill the process will destroy them from the other side.
|
|
273
433
|
await this.process?.kill();
|
package/src/connection.ts
CHANGED
|
@@ -105,7 +105,7 @@ export class ScrcpyClientReverseConnection extends ScrcpyClientConnection {
|
|
|
105
105
|
const writer = queue.writable.getWriter();
|
|
106
106
|
this.address = await this.device.reverse.add(
|
|
107
107
|
'localabstract:scrcpy',
|
|
108
|
-
27183,
|
|
108
|
+
'tcp:27183',
|
|
109
109
|
socket => {
|
|
110
110
|
writer.write(socket);
|
|
111
111
|
return true;
|
package/src/message.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import Struct, { placeholder } from '@yume-chan/struct';
|
|
2
2
|
|
|
3
|
+
// https://github.com/Genymobile/scrcpy/blob/fa5b2a29e983a46b49531def9cf3d80c40c3de37/app/src/control_msg.h#L23
|
|
4
|
+
// For their message bodies, see https://github.com/Genymobile/scrcpy/blob/5c62f3419d252d10cd8c9cbb7c918b358b81f2d0/app/src/control_msg.c#L92
|
|
3
5
|
export enum ScrcpyControlMessageType {
|
|
4
6
|
InjectKeycode,
|
|
5
7
|
InjectText,
|
|
@@ -7,6 +9,7 @@ export enum ScrcpyControlMessageType {
|
|
|
7
9
|
InjectScroll,
|
|
8
10
|
BackOrScreenOn,
|
|
9
11
|
ExpandNotificationPanel,
|
|
12
|
+
ExpandSettingPanel,
|
|
10
13
|
CollapseNotificationPanel,
|
|
11
14
|
GetClipboard,
|
|
12
15
|
SetClipboard,
|
|
@@ -31,9 +34,13 @@ export enum AndroidMotionEventAction {
|
|
|
31
34
|
ButtonRelease,
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
export const ScrcpySimpleControlMessage =
|
|
38
|
+
new Struct()
|
|
39
|
+
.uint8('type');
|
|
40
|
+
|
|
34
41
|
export const ScrcpyInjectTouchControlMessage =
|
|
35
42
|
new Struct()
|
|
36
|
-
.
|
|
43
|
+
.fields(ScrcpySimpleControlMessage)
|
|
37
44
|
.uint8('action', placeholder<AndroidMotionEventAction>())
|
|
38
45
|
.uint64('pointerId')
|
|
39
46
|
.uint32('pointerX')
|
|
@@ -47,7 +54,7 @@ export type ScrcpyInjectTouchControlMessage = typeof ScrcpyInjectTouchControlMes
|
|
|
47
54
|
|
|
48
55
|
export const ScrcpyInjectTextControlMessage =
|
|
49
56
|
new Struct()
|
|
50
|
-
.
|
|
57
|
+
.fields(ScrcpySimpleControlMessage)
|
|
51
58
|
.uint32('length')
|
|
52
59
|
.string('text', { lengthField: 'length' });
|
|
53
60
|
|
|
@@ -95,7 +102,7 @@ export enum AndroidKeyCode {
|
|
|
95
102
|
|
|
96
103
|
export const ScrcpyInjectKeyCodeControlMessage =
|
|
97
104
|
new Struct()
|
|
98
|
-
.
|
|
105
|
+
.fields(ScrcpySimpleControlMessage)
|
|
99
106
|
.uint8('action', placeholder<AndroidKeyEventAction>())
|
|
100
107
|
.uint32('keyCode')
|
|
101
108
|
.uint32('repeat')
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { StructDeserializeStream, TransformStream, type Adb } from "@yume-chan/adb";
|
|
2
|
-
import Struct
|
|
2
|
+
import Struct from "@yume-chan/struct";
|
|
3
3
|
import type { AndroidCodecLevel, AndroidCodecProfile } from "../../codec.js";
|
|
4
4
|
import { ScrcpyClientConnection, ScrcpyClientForwardConnection, ScrcpyClientReverseConnection, type ScrcpyClientConnectionOptions } from "../../connection.js";
|
|
5
|
-
import { AndroidKeyEventAction, ScrcpyControlMessageType } from "../../message.js";
|
|
5
|
+
import { AndroidKeyEventAction, ScrcpyControlMessageType, ScrcpySimpleControlMessage } from "../../message.js";
|
|
6
6
|
import type { ScrcpyBackOrScreenOnEvent1_18 } from "../1_18.js";
|
|
7
7
|
import type { ScrcpyInjectScrollControlMessage1_22 } from "../1_22.js";
|
|
8
8
|
import { toScrcpyOptionValue, type ScrcpyOptions, type ScrcpyOptionValue, type VideoStreamPacket } from "../common.js";
|
|
@@ -16,7 +16,7 @@ export enum ScrcpyLogLevel {
|
|
|
16
16
|
Error = 'error',
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export enum
|
|
19
|
+
export enum ScrcpyVideoOrientation {
|
|
20
20
|
Initial = -2,
|
|
21
21
|
Unlocked = -1,
|
|
22
22
|
Portrait = 0,
|
|
@@ -75,7 +75,7 @@ export interface ScrcpyOptionsInit1_16 {
|
|
|
75
75
|
* It will not keep the device screen in specific orientation,
|
|
76
76
|
* only the captured video will in this orientation.
|
|
77
77
|
*/
|
|
78
|
-
lockVideoOrientation:
|
|
78
|
+
lockVideoOrientation: ScrcpyVideoOrientation;
|
|
79
79
|
|
|
80
80
|
tunnelForward: boolean;
|
|
81
81
|
|
|
@@ -119,12 +119,11 @@ export const VideoPacket =
|
|
|
119
119
|
export const NO_PTS = BigInt(1) << BigInt(63);
|
|
120
120
|
|
|
121
121
|
export const ScrcpyBackOrScreenOnEvent1_16 =
|
|
122
|
-
|
|
123
|
-
.uint8('type', placeholder<ScrcpyControlMessageType.BackOrScreenOn>());
|
|
122
|
+
ScrcpySimpleControlMessage;
|
|
124
123
|
|
|
125
124
|
export const ScrcpyInjectScrollControlMessage1_16 =
|
|
126
125
|
new Struct()
|
|
127
|
-
.
|
|
126
|
+
.fields(ScrcpySimpleControlMessage)
|
|
128
127
|
.uint32('pointerX')
|
|
129
128
|
.uint32('pointerY')
|
|
130
129
|
.uint16('screenWidth')
|
|
@@ -142,8 +141,8 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
if (new.target === ScrcpyOptions1_16 &&
|
|
145
|
-
value.lockVideoOrientation ===
|
|
146
|
-
value.lockVideoOrientation =
|
|
144
|
+
value.lockVideoOrientation === ScrcpyVideoOrientation.Initial) {
|
|
145
|
+
value.lockVideoOrientation = ScrcpyVideoOrientation.Unlocked;
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
this.value = value as Partial<T>;
|
|
@@ -174,7 +173,7 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
174
173
|
maxSize: 0,
|
|
175
174
|
bitRate: 8_000_000,
|
|
176
175
|
maxFps: 0,
|
|
177
|
-
lockVideoOrientation:
|
|
176
|
+
lockVideoOrientation: ScrcpyVideoOrientation.Unlocked,
|
|
178
177
|
tunnelForward: false,
|
|
179
178
|
crop: '-',
|
|
180
179
|
sendFrameMeta: true,
|
|
@@ -297,6 +296,22 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
297
296
|
};
|
|
298
297
|
}
|
|
299
298
|
|
|
299
|
+
public getControlMessageTypes(): ScrcpyControlMessageType[] {
|
|
300
|
+
return [
|
|
301
|
+
/* 0 */ ScrcpyControlMessageType.InjectKeycode,
|
|
302
|
+
/* 1 */ ScrcpyControlMessageType.InjectText,
|
|
303
|
+
/* 2 */ ScrcpyControlMessageType.InjectTouch,
|
|
304
|
+
/* 3 */ ScrcpyControlMessageType.InjectScroll,
|
|
305
|
+
/* 4 */ ScrcpyControlMessageType.BackOrScreenOn,
|
|
306
|
+
/* 5 */ ScrcpyControlMessageType.ExpandNotificationPanel,
|
|
307
|
+
/* 6 */ ScrcpyControlMessageType.CollapseNotificationPanel,
|
|
308
|
+
/* 7 */ ScrcpyControlMessageType.GetClipboard,
|
|
309
|
+
/* 8 */ ScrcpyControlMessageType.SetClipboard,
|
|
310
|
+
/* 9 */ ScrcpyControlMessageType.SetScreenPowerMode,
|
|
311
|
+
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
|
|
300
315
|
public serializeBackOrScreenOnControlMessage(
|
|
301
316
|
message: ScrcpyBackOrScreenOnEvent1_18,
|
|
302
317
|
) {
|
package/src/options/1_18.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Struct, { placeholder } from "@yume-chan/struct";
|
|
2
|
-
import
|
|
2
|
+
import { AndroidKeyEventAction, ScrcpyControlMessageType } from "../message.js";
|
|
3
3
|
import { ScrcpyBackOrScreenOnEvent1_16, ScrcpyOptions1_16, type ScrcpyOptionsInit1_16 } from "./1_16/index.js";
|
|
4
4
|
|
|
5
5
|
export interface ScrcpyOptionsInit1_18 extends ScrcpyOptionsInit1_16 {
|
|
@@ -33,6 +33,26 @@ export class ScrcpyOptions1_18<T extends ScrcpyOptionsInit1_18 = ScrcpyOptionsIn
|
|
|
33
33
|
return /\s+scrcpy --encoder '(.*?)'/;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
public override getControlMessageTypes(): ScrcpyControlMessageType[] {
|
|
37
|
+
/**
|
|
38
|
+
* 0 InjectKeycode
|
|
39
|
+
* 1 InjectText
|
|
40
|
+
* 2 InjectTouch
|
|
41
|
+
* 3 InjectScroll
|
|
42
|
+
* 4 BackOrScreenOn
|
|
43
|
+
* 5 ExpandNotificationPanel
|
|
44
|
+
* 6 ExpandSettingsPanel
|
|
45
|
+
* 7 CollapseNotificationPanel
|
|
46
|
+
* 8 GetClipboard
|
|
47
|
+
* 9 SetClipboard
|
|
48
|
+
* 10 SetScreenPowerMode
|
|
49
|
+
* 11 RotateDevice
|
|
50
|
+
*/
|
|
51
|
+
const types = super.getControlMessageTypes();
|
|
52
|
+
types.splice(6, 0, ScrcpyControlMessageType.ExpandSettingPanel);
|
|
53
|
+
return types;
|
|
54
|
+
}
|
|
55
|
+
|
|
36
56
|
public override serializeBackOrScreenOnControlMessage(
|
|
37
57
|
message: ScrcpyBackOrScreenOnEvent1_18,
|
|
38
58
|
) {
|
package/src/options/1_22.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Adb } from "@yume-chan/adb";
|
|
2
2
|
import Struct from "@yume-chan/struct";
|
|
3
|
-
import { ScrcpyClientForwardConnection, ScrcpyClientReverseConnection, type ScrcpyClientConnection
|
|
3
|
+
import { ScrcpyClientForwardConnection, ScrcpyClientReverseConnection, type ScrcpyClientConnection } from "../connection.js";
|
|
4
4
|
import { ScrcpyInjectScrollControlMessage1_16 } from "./1_16/index.js";
|
|
5
5
|
import { ScrcpyOptions1_21, type ScrcpyOptionsInit1_21 } from "./1_21.js";
|
|
6
6
|
|
|
@@ -8,14 +8,14 @@ export interface ScrcpyOptionsInit1_22 extends ScrcpyOptionsInit1_21 {
|
|
|
8
8
|
downsizeOnError: boolean;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Send device name and size
|
|
11
|
+
* Send device name and size at start of video stream.
|
|
12
12
|
*
|
|
13
13
|
* @default true
|
|
14
14
|
*/
|
|
15
15
|
sendDeviceMeta: boolean;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Send a `0` byte on start of video stream to detect connection issues
|
|
19
19
|
*
|
|
20
20
|
* @default true
|
|
21
21
|
*/
|
|
@@ -59,11 +59,9 @@ export class ScrcpyOptions1_22<T extends ScrcpyOptionsInit1_22 = ScrcpyOptionsIn
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public override createConnection(device: Adb): ScrcpyClientConnection {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sendDummyByte: this.value.sendDummyByte ?? defaultValue.sendDummyByte,
|
|
66
|
-
sendDeviceMeta: this.value.sendDeviceMeta ?? defaultValue.sendDeviceMeta,
|
|
62
|
+
const options = {
|
|
63
|
+
...this.getDefaultValue(),
|
|
64
|
+
...this.value,
|
|
67
65
|
};
|
|
68
66
|
if (this.value.tunnelForward) {
|
|
69
67
|
return new ScrcpyClientForwardConnection(device, options);
|
package/src/options/common.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Adb, TransformStream } from "@yume-chan/adb";
|
|
2
2
|
import type { ScrcpyClientConnection } from "../connection.js";
|
|
3
3
|
import type { H264Configuration } from "../decoder/index.js";
|
|
4
|
+
import type { ScrcpyControlMessageType } from "../message.js";
|
|
4
5
|
import type { ScrcpyBackOrScreenOnEvent1_18 } from "./1_18.js";
|
|
5
6
|
import type { ScrcpyInjectScrollControlMessage1_22 } from "./1_22.js";
|
|
6
7
|
|
|
@@ -53,6 +54,8 @@ export interface ScrcpyOptions<T> {
|
|
|
53
54
|
|
|
54
55
|
createVideoStreamTransformer(): TransformStream<Uint8Array, VideoStreamPacket>;
|
|
55
56
|
|
|
57
|
+
getControlMessageTypes(): ScrcpyControlMessageType[];
|
|
58
|
+
|
|
56
59
|
serializeBackOrScreenOnControlMessage(
|
|
57
60
|
message: ScrcpyBackOrScreenOnEvent1_18,
|
|
58
61
|
): Uint8Array | undefined;
|