mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 09:49:24 +02:00
fix(scrcpy): fix UHID output stream from server version 2.6
This commit also replaced `ScrcpyOptions`'s `parseDeviceMessage`/`endDeviceMessageStream` methods with `deviceMessageParsers`. If you are using that two methods directly, you need to move to the new API
This commit is contained in:
parent
eff718ce36
commit
7edd616b43
28 changed files with 341 additions and 555 deletions
6
.changeset/chilly-parents-build.md
Normal file
6
.changeset/chilly-parents-build.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
"@yume-chan/adb-scrcpy": patch
|
||||||
|
"@yume-chan/scrcpy": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix UHID output stream doesn't work from server version 2.6
|
|
@ -25,6 +25,7 @@ import {
|
||||||
PushReadableStream,
|
PushReadableStream,
|
||||||
SplitStringStream,
|
SplitStringStream,
|
||||||
TextDecoderStream,
|
TextDecoderStream,
|
||||||
|
tryCancel,
|
||||||
WritableStream,
|
WritableStream,
|
||||||
} from "@yume-chan/stream-extra";
|
} from "@yume-chan/stream-extra";
|
||||||
import { ExactReadableEndedError } from "@yume-chan/struct";
|
import { ExactReadableEndedError } from "@yume-chan/struct";
|
||||||
|
@ -321,22 +322,24 @@ export class AdbScrcpyClient<TOptions extends AdbScrcpyOptions<object>> {
|
||||||
const buffered = new BufferedReadableStream(controlStream);
|
const buffered = new BufferedReadableStream(controlStream);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
let type: number;
|
let id: number;
|
||||||
try {
|
try {
|
||||||
const result = await buffered.readExactly(1);
|
const result = await buffered.readExactly(1);
|
||||||
type = result[0]!;
|
id = result[0]!;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ExactReadableEndedError) {
|
if (e instanceof ExactReadableEndedError) {
|
||||||
this.#options.endDeviceMessageStream();
|
this.#options.deviceMessageParsers.close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
await this.#options.parseDeviceMessage(type, buffered);
|
|
||||||
|
await this.#options.deviceMessageParsers.parse(id, buffered);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.#options.endDeviceMessageStream(e);
|
this.#options.deviceMessageParsers.error(e);
|
||||||
buffered.cancel(e).catch(() => {});
|
await tryCancel(buffered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ export class ClipboardStream
|
||||||
{
|
{
|
||||||
#controller: PushReadableStreamController<string>;
|
#controller: PushReadableStreamController<string>;
|
||||||
|
|
||||||
|
readonly id = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
let controller!: PushReadableStreamController<string>;
|
let controller!: PushReadableStreamController<string>;
|
||||||
super((controller_) => {
|
super((controller_) => {
|
||||||
|
@ -24,13 +26,9 @@ export class ClipboardStream
|
||||||
this.#controller = controller;
|
this.#controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parse(id: number, stream: AsyncExactReadable): Promise<boolean> {
|
async parse(_id: number, stream: AsyncExactReadable): Promise<undefined> {
|
||||||
if (id === 0) {
|
const message = await ClipboardDeviceMessage.deserialize(stream);
|
||||||
const message = await ClipboardDeviceMessage.deserialize(stream);
|
await this.#controller.enqueue(message.content);
|
||||||
await this.#controller.enqueue(message.content);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -10,6 +9,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -47,11 +47,18 @@ export class ScrcpyOptions1_15 implements ScrcpyOptions<Init> {
|
||||||
return this.#clipboard;
|
return this.#clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,25 +80,6 @@ export class ScrcpyOptions1_15 implements ScrcpyOptions<Init> {
|
||||||
return parseVideoStreamMetadata(stream);
|
return parseVideoStreamMetadata(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard!.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard!.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard!.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -54,11 +54,18 @@ export class ScrcpyOptions1_17
|
||||||
return this.#clipboard;
|
return this.#clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,25 +95,6 @@ export class ScrcpyOptions1_17
|
||||||
return parseVideoStreamMetadata(stream);
|
return parseVideoStreamMetadata(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard!.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard!.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard!.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -54,11 +54,18 @@ export class ScrcpyOptions1_18
|
||||||
return this.#clipboard;
|
return this.#clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,25 +95,6 @@ export class ScrcpyOptions1_18
|
||||||
return parseVideoStreamMetadata(stream);
|
return parseVideoStreamMetadata(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard!.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard!.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard!.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -29,18 +29,15 @@ export class AckClipboardHandler implements ScrcpyDeviceMessageParser {
|
||||||
|
|
||||||
#closed = false;
|
#closed = false;
|
||||||
|
|
||||||
async parse(id: number, stream: AsyncExactReadable) {
|
readonly id = 1;
|
||||||
if (id !== 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
async parse(_id: number, stream: AsyncExactReadable): Promise<undefined> {
|
||||||
const message = await AckClipboardDeviceMessage.deserialize(stream);
|
const message = await AckClipboardDeviceMessage.deserialize(stream);
|
||||||
const resolver = this.#resolvers.get(message.sequence);
|
const resolver = this.#resolvers.get(message.sequence);
|
||||||
if (resolver) {
|
if (resolver) {
|
||||||
resolver.resolve();
|
resolver.resolve();
|
||||||
this.#resolvers.delete(message.sequence);
|
this.#resolvers.delete(message.sequence);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -55,12 +55,22 @@ export class ScrcpyOptions1_21
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,31 +100,6 @@ export class ScrcpyOptions1_21
|
||||||
return parseVideoStreamMetadata(stream);
|
return parseVideoStreamMetadata(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -55,12 +55,22 @@ export class ScrcpyOptions1_22
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,31 +100,6 @@ export class ScrcpyOptions1_22
|
||||||
return parseVideoStreamMetadata(this.value, stream);
|
return parseVideoStreamMetadata(this.value, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -55,12 +55,22 @@ export class ScrcpyOptions1_23
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,31 +100,6 @@ export class ScrcpyOptions1_23
|
||||||
return parseVideoStreamMetadata(this.value, stream);
|
return parseVideoStreamMetadata(this.value, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -55,12 +55,22 @@ export class ScrcpyOptions1_24
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,31 +100,6 @@ export class ScrcpyOptions1_24
|
||||||
return parseVideoStreamMetadata(this.value, stream);
|
return parseVideoStreamMetadata(this.value, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyControlMessageType,
|
ScrcpyControlMessageType,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -55,12 +55,22 @@ export class ScrcpyOptions1_25
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,31 +100,6 @@ export class ScrcpyOptions1_25
|
||||||
return parseVideoStreamMetadata(this.value, stream);
|
return parseVideoStreamMetadata(this.value, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -56,12 +56,22 @@ export class ScrcpyOptions2_0
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,31 +107,6 @@ export class ScrcpyOptions2_0
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -56,12 +56,22 @@ export class ScrcpyOptions2_1<TVideo extends boolean>
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,31 +107,6 @@ export class ScrcpyOptions2_1<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -56,6 +56,11 @@ export class ScrcpyOptions2_2<TVideo extends boolean>
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -64,8 +69,13 @@ export class ScrcpyOptions2_2<TVideo extends boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,31 +111,6 @@ export class ScrcpyOptions2_2<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -56,6 +56,11 @@ export class ScrcpyOptions2_3<TVideo extends boolean>
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -64,8 +69,13 @@ export class ScrcpyOptions2_3<TVideo extends boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,31 +111,6 @@ export class ScrcpyOptions2_3<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -23,6 +23,8 @@ export class UHidOutputStream
|
||||||
{
|
{
|
||||||
#controller: PushReadableStreamController<UHidOutputDeviceMessage>;
|
#controller: PushReadableStreamController<UHidOutputDeviceMessage>;
|
||||||
|
|
||||||
|
readonly id = 2;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
let controller!: PushReadableStreamController<UHidOutputDeviceMessage>;
|
let controller!: PushReadableStreamController<UHidOutputDeviceMessage>;
|
||||||
super((controller_) => {
|
super((controller_) => {
|
||||||
|
@ -31,14 +33,9 @@ export class UHidOutputStream
|
||||||
this.#controller = controller;
|
this.#controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
async parse(id: number, stream: AsyncExactReadable): Promise<boolean> {
|
async parse(_id: number, stream: AsyncExactReadable): Promise<undefined> {
|
||||||
if (id !== 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = await UHidOutputDeviceMessage.deserialize(stream);
|
const message = await UHidOutputDeviceMessage.deserialize(stream);
|
||||||
await this.#controller.enqueue(message);
|
await this.#controller.enqueue(message);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -67,6 +67,11 @@ export class ScrcpyOptions2_4<TVideo extends boolean>
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -76,11 +81,18 @@ export class ScrcpyOptions2_4<TVideo extends boolean>
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#uHidOutput = new UHidOutputStream();
|
this.#uHidOutput = this.#deviceMessageParsers.add(
|
||||||
|
new UHidOutputStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,37 +128,6 @@ export class ScrcpyOptions2_4<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#uHidOutput?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
this.#uHidOutput?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
this.#uHidOutput?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -67,6 +67,11 @@ export class ScrcpyOptions2_6<TVideo extends boolean>
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -80,11 +85,18 @@ export class ScrcpyOptions2_6<TVideo extends boolean>
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#uHidOutput = new UHidOutputStream();
|
this.#uHidOutput = this.#deviceMessageParsers.add(
|
||||||
|
new UHidOutputStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,31 +132,6 @@ export class ScrcpyOptions2_6<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { buffer, string, struct, u16, u8 } from "@yume-chan/struct";
|
import { buffer, string, struct, u16, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { ScrcpyControlMessageType } from "../../base/control-message-type.js";
|
|
||||||
import type { ScrcpyUHidCreateControlMessage } from "../../latest.js";
|
import type { ScrcpyUHidCreateControlMessage } from "../../latest.js";
|
||||||
|
|
||||||
export const UHidCreateControlMessage = /* #__PURE__ */ (() =>
|
export const UHidCreateControlMessage = struct(
|
||||||
struct(
|
{
|
||||||
{
|
type: u8,
|
||||||
type: u8(ScrcpyControlMessageType.UHidCreate),
|
id: u16,
|
||||||
id: u16,
|
name: string(u8),
|
||||||
name: string(u8),
|
data: buffer(u16),
|
||||||
data: buffer(u16),
|
},
|
||||||
},
|
{ littleEndian: false },
|
||||||
{ littleEndian: false },
|
);
|
||||||
))();
|
|
||||||
|
|
||||||
export type UHidCreateControlMessage = StructInit<
|
export type UHidCreateControlMessage = StructInit<
|
||||||
typeof UHidCreateControlMessage
|
typeof UHidCreateControlMessage
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -67,6 +67,11 @@ export class ScrcpyOptions2_7<TVideo extends boolean>
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -80,11 +85,18 @@ export class ScrcpyOptions2_7<TVideo extends boolean>
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#uHidOutput = new UHidOutputStream();
|
this.#uHidOutput = this.#deviceMessageParsers.add(
|
||||||
|
new UHidOutputStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,31 +132,6 @@ export class ScrcpyOptions2_7<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -67,6 +67,11 @@ export class ScrcpyOptions3_0<TVideo extends boolean>
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -80,11 +85,18 @@ export class ScrcpyOptions3_0<TVideo extends boolean>
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#uHidOutput = new UHidOutputStream();
|
this.#uHidOutput = this.#deviceMessageParsers.add(
|
||||||
|
new UHidOutputStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,31 +132,6 @@ export class ScrcpyOptions3_0<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { buffer, string, struct, u16, u8 } from "@yume-chan/struct";
|
import { buffer, string, struct, u16, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { ScrcpyControlMessageType } from "../../base/control-message-type.js";
|
|
||||||
import type { ScrcpyUHidCreateControlMessage } from "../../latest.js";
|
import type { ScrcpyUHidCreateControlMessage } from "../../latest.js";
|
||||||
|
|
||||||
export const UHidCreateControlMessage = /* #__PURE__ */ (() =>
|
export const UHidCreateControlMessage = struct(
|
||||||
struct(
|
{
|
||||||
{
|
type: u8,
|
||||||
type: u8(ScrcpyControlMessageType.UHidCreate),
|
id: u16,
|
||||||
id: u16,
|
vendorId: u16,
|
||||||
vendorId: u16,
|
productId: u16,
|
||||||
productId: u16,
|
name: string(u8),
|
||||||
name: string(u8),
|
data: buffer(u16),
|
||||||
data: buffer(u16),
|
},
|
||||||
},
|
{ littleEndian: false },
|
||||||
{ littleEndian: false },
|
);
|
||||||
))();
|
|
||||||
|
|
||||||
export type UHidCreateControlMessage = StructInit<
|
export type UHidCreateControlMessage = StructInit<
|
||||||
typeof UHidCreateControlMessage
|
typeof UHidCreateControlMessage
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -67,6 +67,11 @@ export class ScrcpyOptions3_1<TVideo extends boolean>
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -80,11 +85,18 @@ export class ScrcpyOptions3_1<TVideo extends boolean>
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#uHidOutput = new UHidOutputStream();
|
this.#uHidOutput = this.#deviceMessageParsers.add(
|
||||||
|
new UHidOutputStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,31 +132,6 @@ export class ScrcpyOptions3_1<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyAudioStreamMetadata,
|
ScrcpyAudioStreamMetadata,
|
||||||
|
@ -13,6 +12,7 @@ import type {
|
||||||
ScrcpyScrollController,
|
ScrcpyScrollController,
|
||||||
ScrcpyVideoStream,
|
ScrcpyVideoStream,
|
||||||
} from "../base/index.js";
|
} from "../base/index.js";
|
||||||
|
import { ScrcpyDeviceMessageParsers } from "../base/index.js";
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
|
@ -67,6 +67,11 @@ export class ScrcpyOptions3_2<TVideo extends boolean>
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
|
||||||
|
get deviceMessageParsers() {
|
||||||
|
return this.#deviceMessageParsers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init<TVideo>) {
|
constructor(init: Init<TVideo>) {
|
||||||
this.value = { ...Defaults, ...init } as never;
|
this.value = { ...Defaults, ...init } as never;
|
||||||
|
|
||||||
|
@ -80,11 +85,18 @@ export class ScrcpyOptions3_2<TVideo extends boolean>
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = this.#deviceMessageParsers.add(
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
new ClipboardStream(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ackClipboardHandler = this.#deviceMessageParsers.add(
|
||||||
|
new AckClipboardHandler(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#uHidOutput = new UHidOutputStream();
|
this.#uHidOutput = this.#deviceMessageParsers.add(
|
||||||
|
new UHidOutputStream(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,31 +132,6 @@ export class ScrcpyOptions3_2<TVideo extends boolean>
|
||||||
return parseAudioStreamMetadata(stream, this.value);
|
return parseAudioStreamMetadata(stream, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void> {
|
|
||||||
if (await this.#clipboard?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await this.#ackClipboardHandler?.parse(id, stream)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("Unknown device message");
|
|
||||||
}
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void {
|
|
||||||
if (e) {
|
|
||||||
this.#clipboard?.error(e);
|
|
||||||
this.#ackClipboardHandler?.error(e);
|
|
||||||
} else {
|
|
||||||
this.#clipboard?.close();
|
|
||||||
this.#ackClipboardHandler?.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -1,9 +1,58 @@
|
||||||
import type { AsyncExactReadable } from "@yume-chan/struct";
|
import type { AsyncExactReadable } from "@yume-chan/struct";
|
||||||
|
|
||||||
export interface ScrcpyDeviceMessageParser {
|
export interface ScrcpyDeviceMessageParser {
|
||||||
parse(id: number, stream: AsyncExactReadable): Promise<boolean>;
|
readonly id: number | readonly number[];
|
||||||
|
|
||||||
|
parse(id: number, stream: AsyncExactReadable): Promise<undefined>;
|
||||||
|
|
||||||
close(): void;
|
close(): void;
|
||||||
|
|
||||||
error(e?: unknown): void;
|
error(e?: unknown): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ScrcpyDeviceMessageParsers {
|
||||||
|
#parsers: ScrcpyDeviceMessageParser[] = [];
|
||||||
|
get parsers(): readonly ScrcpyDeviceMessageParser[] {
|
||||||
|
return this.#parsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add(id: number, parser: ScrcpyDeviceMessageParser) {
|
||||||
|
if (this.#parsers[id]) {
|
||||||
|
throw new Error(`Duplicate parser for id ${id}`);
|
||||||
|
}
|
||||||
|
this.#parsers[id] = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
add<T extends ScrcpyDeviceMessageParser>(parser: T): T {
|
||||||
|
if (Array.isArray(parser.id)) {
|
||||||
|
for (const id of parser.id) {
|
||||||
|
this.#add(id as number, parser);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.#add(parser.id as number, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
async parse(id: number, stream: AsyncExactReadable): Promise<undefined> {
|
||||||
|
const parser = this.#parsers[id];
|
||||||
|
if (!parser) {
|
||||||
|
throw new Error(`Unknown device message id ${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parser.parse(id, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
for (const parser of this.#parsers) {
|
||||||
|
parser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error(e?: unknown) {
|
||||||
|
for (const parser of this.#parsers) {
|
||||||
|
parser.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { MaybePromiseLike } from "@yume-chan/async";
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
||||||
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, ExactReadable } from "@yume-chan/struct";
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScrcpyBackOrScreenOnControlMessage,
|
ScrcpyBackOrScreenOnControlMessage,
|
||||||
|
@ -12,6 +11,7 @@ import type {
|
||||||
|
|
||||||
import type { ScrcpyAudioStreamMetadata } from "./audio.js";
|
import type { ScrcpyAudioStreamMetadata } from "./audio.js";
|
||||||
import type { ScrcpyControlMessageType } from "./control-message-type.js";
|
import type { ScrcpyControlMessageType } from "./control-message-type.js";
|
||||||
|
import type { ScrcpyDeviceMessageParsers } from "./device-message.js";
|
||||||
import type { ScrcpyDisplay } from "./display.js";
|
import type { ScrcpyDisplay } from "./display.js";
|
||||||
import type { ScrcpyEncoder } from "./encoder.js";
|
import type { ScrcpyEncoder } from "./encoder.js";
|
||||||
import type { ScrcpyMediaStreamPacket } from "./media.js";
|
import type { ScrcpyMediaStreamPacket } from "./media.js";
|
||||||
|
@ -29,6 +29,8 @@ export interface ScrcpyOptions<T extends object> {
|
||||||
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
|
readonly deviceMessageParsers: ScrcpyDeviceMessageParsers;
|
||||||
|
|
||||||
serialize(): string[];
|
serialize(): string[];
|
||||||
|
|
||||||
setListDisplays(): void;
|
setListDisplays(): void;
|
||||||
|
@ -43,13 +45,6 @@ export interface ScrcpyOptions<T extends object> {
|
||||||
stream: ReadableStream<Uint8Array>,
|
stream: ReadableStream<Uint8Array>,
|
||||||
): MaybePromiseLike<ScrcpyAudioStreamMetadata>;
|
): MaybePromiseLike<ScrcpyAudioStreamMetadata>;
|
||||||
|
|
||||||
parseDeviceMessage(
|
|
||||||
id: number,
|
|
||||||
stream: ExactReadable | AsyncExactReadable,
|
|
||||||
): Promise<void>;
|
|
||||||
|
|
||||||
endDeviceMessageStream(e?: unknown): void;
|
|
||||||
|
|
||||||
createMediaStreamTransformer(): TransformStream<
|
createMediaStreamTransformer(): TransformStream<
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
ScrcpyMediaStreamPacket
|
ScrcpyMediaStreamPacket
|
||||||
|
|
|
@ -20,11 +20,11 @@ export class ScrcpyControlMessageTypeMap {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fillMessageType<T extends { type: ScrcpyControlMessageType }>(
|
fillMessageType<T extends { type: number }>(
|
||||||
message: Omit<T, "type">,
|
message: Omit<T, "type">,
|
||||||
type: T["type"],
|
type: ScrcpyControlMessageType,
|
||||||
): T {
|
): T {
|
||||||
(message as T).type = this.get(type) as ScrcpyControlMessageType;
|
(message as T).type = this.get(type);
|
||||||
return message as T;
|
return message as T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue