mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-04 02:09:18 +02:00
refactor(scrcpy): rewrite option classes to improve tree-shaking
This commit is contained in:
parent
92472007db
commit
cc5d52912e
63 changed files with 595 additions and 325 deletions
|
@ -46,6 +46,8 @@ export class AdbScrcpyOptions1_16 extends AdbScrcpyOptions<
|
||||||
const client = await AdbScrcpyClient.start(adb, path, version, options);
|
const client = await AdbScrcpyClient.start(adb, path, version, options);
|
||||||
|
|
||||||
const encoders: ScrcpyEncoder[] = [];
|
const encoders: ScrcpyEncoder[] = [];
|
||||||
|
|
||||||
|
// `client.stdout` is supplied by user and may not support async iteration
|
||||||
await client.stdout.pipeTo(
|
await client.stdout.pipeTo(
|
||||||
new WritableStream({
|
new WritableStream({
|
||||||
write: (line) => {
|
write: (line) => {
|
||||||
|
|
|
@ -2,7 +2,6 @@ import type { MaybeConsumable, WritableStream } from "@yume-chan/stream-extra";
|
||||||
import { ReadableStream } from "@yume-chan/stream-extra";
|
import { ReadableStream } from "@yume-chan/stream-extra";
|
||||||
|
|
||||||
import type { Adb, AdbSocket } from "../../../adb.js";
|
import type { Adb, AdbSocket } from "../../../adb.js";
|
||||||
import { unreachable } from "../../../utils/index.js";
|
|
||||||
|
|
||||||
import type { AdbSubprocessProtocol } from "./types.js";
|
import type { AdbSubprocessProtocol } from "./types.js";
|
||||||
|
|
||||||
|
@ -64,10 +63,9 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
||||||
this.#socket = socket;
|
this.#socket = socket;
|
||||||
|
|
||||||
this.#stderr = new ReadableStream({
|
this.#stderr = new ReadableStream({
|
||||||
start: (controller) => {
|
start: async (controller) => {
|
||||||
this.#socket.closed
|
await this.#socket.closed;
|
||||||
.then(() => controller.close())
|
controller.close();
|
||||||
.catch(unreachable);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.#exit = socket.closed.then(() => 0);
|
this.#exit = socket.closed.then(() => 0);
|
||||||
|
|
|
@ -15,23 +15,25 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncEntryResponse = struct(
|
export const AdbSyncEntryResponse = /* #__PURE__ */ (() =>
|
||||||
/* #__PURE__ */ (() => ({
|
struct(
|
||||||
...AdbSyncLstatResponse.fields,
|
{
|
||||||
name: string(u32),
|
...AdbSyncLstatResponse.fields,
|
||||||
}))(),
|
name: string(u32),
|
||||||
{ littleEndian: true, extra: AdbSyncLstatResponse.extra },
|
},
|
||||||
);
|
{ littleEndian: true, extra: AdbSyncLstatResponse.extra },
|
||||||
|
))();
|
||||||
|
|
||||||
export type AdbSyncEntryResponse = StructValue<typeof AdbSyncEntryResponse>;
|
export type AdbSyncEntryResponse = StructValue<typeof AdbSyncEntryResponse>;
|
||||||
|
|
||||||
export const AdbSyncEntry2Response = struct(
|
export const AdbSyncEntry2Response = /* #__PURE__ */ (() =>
|
||||||
/* #__PURE__ */ (() => ({
|
struct(
|
||||||
...AdbSyncStatResponse.fields,
|
{
|
||||||
name: string(u32),
|
...AdbSyncStatResponse.fields,
|
||||||
}))(),
|
name: string(u32),
|
||||||
{ littleEndian: true, extra: AdbSyncStatResponse.extra },
|
},
|
||||||
);
|
{ littleEndian: true, extra: AdbSyncStatResponse.extra },
|
||||||
|
))();
|
||||||
|
|
||||||
export type AdbSyncEntry2Response = StructValue<typeof AdbSyncEntry2Response>;
|
export type AdbSyncEntry2Response = StructValue<typeof AdbSyncEntry2Response>;
|
||||||
|
|
||||||
|
|
|
@ -43,11 +43,13 @@ export interface AdbCredentialStore {
|
||||||
iterateKeys(): AdbKeyIterable;
|
iterateKeys(): AdbKeyIterable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AdbAuthType {
|
export const AdbAuthType = {
|
||||||
Token = 1,
|
Token: 1,
|
||||||
Signature = 2,
|
Signature: 2,
|
||||||
PublicKey = 3,
|
PublicKey: 3,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type AdbAuthType = (typeof AdbAuthType)[keyof typeof AdbAuthType];
|
||||||
|
|
||||||
export interface AdbAuthenticator {
|
export interface AdbAuthenticator {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -28,27 +28,28 @@ import { AdbCommand, calculateChecksum } from "./packet.js";
|
||||||
export const ADB_DAEMON_VERSION_OMIT_CHECKSUM = 0x01000001;
|
export const ADB_DAEMON_VERSION_OMIT_CHECKSUM = 0x01000001;
|
||||||
// https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
|
// https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
|
||||||
// There are some other feature constants, but some of them are only used by ADB server, not devices (daemons).
|
// There are some other feature constants, but some of them are only used by ADB server, not devices (daemons).
|
||||||
export const ADB_DAEMON_DEFAULT_FEATURES = [
|
export const ADB_DAEMON_DEFAULT_FEATURES = /* #__PURE__ */ (() =>
|
||||||
AdbFeature.ShellV2,
|
[
|
||||||
AdbFeature.Cmd,
|
AdbFeature.ShellV2,
|
||||||
AdbFeature.StatV2,
|
AdbFeature.Cmd,
|
||||||
AdbFeature.ListV2,
|
AdbFeature.StatV2,
|
||||||
AdbFeature.FixedPushMkdir,
|
AdbFeature.ListV2,
|
||||||
"apex",
|
AdbFeature.FixedPushMkdir,
|
||||||
AdbFeature.Abb,
|
"apex",
|
||||||
// only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
|
AdbFeature.Abb,
|
||||||
// No special handling required.
|
// only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
|
||||||
"fixed_push_symlink_timestamp",
|
// No special handling required.
|
||||||
AdbFeature.AbbExec,
|
"fixed_push_symlink_timestamp",
|
||||||
"remount_shell",
|
AdbFeature.AbbExec,
|
||||||
"track_app",
|
"remount_shell",
|
||||||
AdbFeature.SendReceiveV2,
|
"track_app",
|
||||||
"sendrecv_v2_brotli",
|
AdbFeature.SendReceiveV2,
|
||||||
"sendrecv_v2_lz4",
|
"sendrecv_v2_brotli",
|
||||||
"sendrecv_v2_zstd",
|
"sendrecv_v2_lz4",
|
||||||
"sendrecv_v2_dry_run_send",
|
"sendrecv_v2_zstd",
|
||||||
AdbFeature.DelayedAck,
|
"sendrecv_v2_dry_run_send",
|
||||||
] as AdbFeature[];
|
AdbFeature.DelayedAck,
|
||||||
|
] as AdbFeature[])();
|
||||||
export const ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE = 32 * 1024 * 1024;
|
export const ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE = 32 * 1024 * 1024;
|
||||||
|
|
||||||
export type AdbDaemonConnection = ReadableWritablePair<
|
export type AdbDaemonConnection = ReadableWritablePair<
|
||||||
|
|
|
@ -211,37 +211,33 @@ export class BugReport extends AdbCommandBase {
|
||||||
let filename: string | undefined;
|
let filename: string | undefined;
|
||||||
let error: string | undefined;
|
let error: string | undefined;
|
||||||
|
|
||||||
await process.stdout
|
for await (const line of process.stdout
|
||||||
.pipeThrough(new TextDecoderStream())
|
.pipeThrough(new TextDecoderStream())
|
||||||
.pipeThrough(new SplitStringStream("\n"))
|
// Each chunk should contain one or several full lines
|
||||||
.pipeTo(
|
.pipeThrough(new SplitStringStream("\n"))) {
|
||||||
new WritableStream<string>({
|
// `BEGIN:` and `PROGRESS:` only appear when `-p` is specified.
|
||||||
write(line) {
|
let match = line.match(BugReport.PROGRESS_REGEX);
|
||||||
// `BEGIN:` and `PROGRESS:` only appear when `-p` is specified.
|
if (match) {
|
||||||
let match = line.match(BugReport.PROGRESS_REGEX);
|
options?.onProgress?.(match[1]!, match[2]!);
|
||||||
if (match) {
|
}
|
||||||
options?.onProgress?.(match[1]!, match[2]!);
|
|
||||||
}
|
|
||||||
|
|
||||||
match = line.match(BugReport.BEGIN_REGEX);
|
match = line.match(BugReport.BEGIN_REGEX);
|
||||||
if (match) {
|
if (match) {
|
||||||
filename = match[1]!;
|
filename = match[1]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
match = line.match(BugReport.OK_REGEX);
|
match = line.match(BugReport.OK_REGEX);
|
||||||
if (match) {
|
if (match) {
|
||||||
filename = match[1];
|
filename = match[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
match = line.match(BugReport.FAIL_REGEX);
|
match = line.match(BugReport.FAIL_REGEX);
|
||||||
if (match) {
|
if (match) {
|
||||||
// Don't report error now
|
// Don't report error now
|
||||||
// We want to gather all output.
|
// We want to gather all output.
|
||||||
error = match[1];
|
error = match[1];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
|
|
|
@ -8,7 +8,6 @@ import {
|
||||||
SplitStringStream,
|
SplitStringStream,
|
||||||
TextDecoderStream,
|
TextDecoderStream,
|
||||||
WrapReadableStream,
|
WrapReadableStream,
|
||||||
WritableStream,
|
|
||||||
} from "@yume-chan/stream-extra";
|
} from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, StructValue } from "@yume-chan/struct";
|
import type { AsyncExactReadable, StructValue } from "@yume-chan/struct";
|
||||||
import { decodeUtf8, struct, u16, u32 } from "@yume-chan/struct";
|
import { decodeUtf8, struct, u16, u32 } from "@yume-chan/struct";
|
||||||
|
@ -437,53 +436,48 @@ export class Logcat extends AdbCommandBase {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const result: LogSize[] = [];
|
const result: LogSize[] = [];
|
||||||
await stdout
|
for await (const line of stdout
|
||||||
.pipeThrough(new TextDecoderStream())
|
.pipeThrough(new TextDecoderStream())
|
||||||
.pipeThrough(new SplitStringStream("\n"))
|
.pipeThrough(new SplitStringStream("\n"))) {
|
||||||
.pipeTo(
|
let match = line.match(Logcat.LOG_SIZE_REGEX_11);
|
||||||
new WritableStream({
|
if (match) {
|
||||||
write(chunk) {
|
result.push({
|
||||||
let match = chunk.match(Logcat.LOG_SIZE_REGEX_11);
|
id: Logcat.logNameToId(match[1]!),
|
||||||
if (match) {
|
size: Logcat.parseSize(
|
||||||
result.push({
|
Number.parseInt(match[2]!, 10),
|
||||||
id: Logcat.logNameToId(match[1]!),
|
match[3]!,
|
||||||
size: Logcat.parseSize(
|
),
|
||||||
Number.parseInt(match[2]!, 10),
|
readable: Logcat.parseSize(
|
||||||
match[3]!,
|
Number.parseInt(match[6]!, 10),
|
||||||
),
|
match[7]!,
|
||||||
readable: Logcat.parseSize(
|
),
|
||||||
Number.parseInt(match[6]!, 10),
|
consumed: Logcat.parseSize(
|
||||||
match[7]!,
|
Number.parseInt(match[4]!, 10),
|
||||||
),
|
match[5]!,
|
||||||
consumed: Logcat.parseSize(
|
),
|
||||||
Number.parseInt(match[4]!, 10),
|
maxEntrySize: parseInt(match[8]!, 10),
|
||||||
match[5]!,
|
maxPayloadSize: parseInt(match[9]!, 10),
|
||||||
),
|
});
|
||||||
maxEntrySize: parseInt(match[8]!, 10),
|
break;
|
||||||
maxPayloadSize: parseInt(match[9]!, 10),
|
}
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match = chunk.match(Logcat.LOG_SIZE_REGEX_10);
|
match = line.match(Logcat.LOG_SIZE_REGEX_10);
|
||||||
if (match) {
|
if (match) {
|
||||||
result.push({
|
result.push({
|
||||||
id: Logcat.logNameToId(match[1]!),
|
id: Logcat.logNameToId(match[1]!),
|
||||||
size: Logcat.parseSize(
|
size: Logcat.parseSize(
|
||||||
Number.parseInt(match[2]!, 10),
|
Number.parseInt(match[2]!, 10),
|
||||||
match[3]!,
|
match[3]!,
|
||||||
),
|
),
|
||||||
consumed: Logcat.parseSize(
|
consumed: Logcat.parseSize(
|
||||||
Number.parseInt(match[4]!, 10),
|
Number.parseInt(match[4]!, 10),
|
||||||
match[5]!,
|
match[5]!,
|
||||||
),
|
),
|
||||||
maxEntrySize: parseInt(match[6]!, 10),
|
maxEntrySize: parseInt(match[6]!, 10),
|
||||||
maxPayloadSize: parseInt(match[7]!, 10),
|
maxPayloadSize: parseInt(match[7]!, 10),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export * from "../../esm/index";
|
|
|
@ -6,7 +6,7 @@ export const VideoOrientation = {
|
||||||
Landscape: 1,
|
Landscape: 1,
|
||||||
PortraitFlipped: 2,
|
PortraitFlipped: 2,
|
||||||
LandscapeFlipped: 3,
|
LandscapeFlipped: 3,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type VideoOrientation =
|
export type VideoOrientation =
|
||||||
(typeof VideoOrientation)[keyof typeof VideoOrientation];
|
(typeof VideoOrientation)[keyof typeof VideoOrientation];
|
||||||
|
@ -85,6 +85,10 @@ export class CodecOptions implements ScrcpyOptionValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace CodecOptions {
|
||||||
|
export type Init = CodecOptionsInit;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Init {
|
export interface Init {
|
||||||
logLevel?: LogLevel;
|
logLevel?: LogLevel;
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,7 @@ import { bipedal, struct, u16, u32, u64, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { AndroidMotionEventAction } from "../../android/index.js";
|
import type { AndroidMotionEventAction } from "../../android/index.js";
|
||||||
import type { ScrcpyInjectTouchControlMessage } from "../../latest.js";
|
import type { ScrcpyInjectTouchControlMessage } from "../../latest.js";
|
||||||
|
import { clamp } from "../../utils/index.js";
|
||||||
export function clamp(value: number, min: number, max: number): number {
|
|
||||||
if (value < min) {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value > max) {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UnsignedFloat: Field<number, never, never> = {
|
export const UnsignedFloat: Field<number, never, never> = {
|
||||||
size: 2,
|
size: 2,
|
||||||
|
@ -33,6 +22,13 @@ export const UnsignedFloat: Field<number, never, never> = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PointerId = {
|
||||||
|
Mouse: -1n,
|
||||||
|
Finger: -2n,
|
||||||
|
VirtualMouse: -3n,
|
||||||
|
VirtualFinger: -4n,
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const InjectTouchControlMessage = struct(
|
export const InjectTouchControlMessage = struct(
|
||||||
{
|
{
|
||||||
type: u8,
|
type: u8,
|
||||||
|
|
|
@ -5,6 +5,7 @@ export {
|
||||||
} from "./back-or-screen-on.js";
|
} from "./back-or-screen-on.js";
|
||||||
export { ControlMessageTypes } from "./control-message-types.js";
|
export { ControlMessageTypes } from "./control-message-types.js";
|
||||||
export { Defaults } from "./defaults.js";
|
export { Defaults } from "./defaults.js";
|
||||||
export type { Init } from "./init.js";
|
export { VideoOrientation } from "./init.js";
|
||||||
|
export type { Init, LogLevel } from "./init.js";
|
||||||
export { EncoderRegex } from "./parse-encoder.js";
|
export { EncoderRegex } from "./parse-encoder.js";
|
||||||
export { SerializeOrder } from "./serialize-order.js";
|
export { SerializeOrder } from "./serialize-order.js";
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const VideoOrientation = {
|
||||||
Landscape: 1,
|
Landscape: 1,
|
||||||
PortraitFlipped: 2,
|
PortraitFlipped: 2,
|
||||||
LandscapeFlipped: 3,
|
LandscapeFlipped: 3,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type VideoOrientation =
|
export type VideoOrientation =
|
||||||
(typeof VideoOrientation)[keyof typeof VideoOrientation];
|
(typeof VideoOrientation)[keyof typeof VideoOrientation];
|
||||||
|
|
|
@ -4,15 +4,16 @@ function toSnakeCase(input: string): string {
|
||||||
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1.21 changed the format of arguments
|
||||||
export function serialize<T extends object>(
|
export function serialize<T extends object>(
|
||||||
options: T,
|
options: T,
|
||||||
defaults: Required<T>,
|
defaults: Required<T>,
|
||||||
): string[] {
|
): string[] {
|
||||||
// 1.21 changed the format of arguments
|
|
||||||
const result: string[] = [];
|
const result: string[] = [];
|
||||||
for (const [key, value] of Object.entries(options)) {
|
for (const [key, value] of Object.entries(options)) {
|
||||||
const serializedValue = toScrcpyOptionValue(value, undefined);
|
const serializedValue = toScrcpyOptionValue(value, undefined);
|
||||||
if (!serializedValue) {
|
// v3.0 `new_display` option needs to send empty strings to server
|
||||||
|
if (serializedValue === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ export function serialize<T extends object>(
|
||||||
defaults[key as keyof T],
|
defaults[key as keyof T],
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
if (serializedValue == defaultValue) {
|
if (serializedValue === defaultValue) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { s32, struct } from "@yume-chan/struct";
|
import { s32, struct } from "@yume-chan/struct";
|
||||||
|
|
||||||
|
import type { ScrcpyInjectScrollControlMessage } from "../../latest.js";
|
||||||
|
|
||||||
import { PrevImpl } from "./prev.js";
|
import { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export const InjectScrollControlMessage = /* #__PURE__ */ (() =>
|
export const InjectScrollControlMessage = /* #__PURE__ */ (() =>
|
||||||
|
@ -18,7 +20,7 @@ export type InjectScrollControlMessage = StructInit<
|
||||||
|
|
||||||
export class ScrollController extends PrevImpl.ScrollController {
|
export class ScrollController extends PrevImpl.ScrollController {
|
||||||
override serializeScrollMessage(
|
override serializeScrollMessage(
|
||||||
message: InjectScrollControlMessage,
|
message: ScrcpyInjectScrollControlMessage,
|
||||||
): Uint8Array | undefined {
|
): Uint8Array | undefined {
|
||||||
const processed = this.processMessage(message);
|
const processed = this.processMessage(message);
|
||||||
if (!processed) {
|
if (!processed) {
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { getInt16, setInt16 } from "@yume-chan/no-data-view";
|
||||||
import type { Field, StructInit } from "@yume-chan/struct";
|
import type { Field, StructInit } from "@yume-chan/struct";
|
||||||
import { bipedal, struct, u16, u32, u8 } from "@yume-chan/struct";
|
import { bipedal, struct, u16, u32, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
|
import { ScrcpyControlMessageType } from "../../base/index.js";
|
||||||
import type { ScrcpyScrollController } from "../../base/index.js";
|
import type { ScrcpyScrollController } from "../../base/index.js";
|
||||||
import type { ScrcpyInjectScrollControlMessage } from "../../latest.js";
|
import type { ScrcpyInjectScrollControlMessage } from "../../latest.js";
|
||||||
|
import { clamp } from "../../utils/index.js";
|
||||||
import { PrevImpl } from "./prev.js";
|
|
||||||
|
|
||||||
export const SignedFloat: Field<number, never, never> = {
|
export const SignedFloat: Field<number, never, never> = {
|
||||||
size: 2,
|
size: 2,
|
||||||
serialize(value, { buffer, index, littleEndian }) {
|
serialize(value, { buffer, index, littleEndian }) {
|
||||||
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L51
|
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L51
|
||||||
value = PrevImpl.clamp(value, -1, 1);
|
value = clamp(value, -1, 1);
|
||||||
value = value === 1 ? 0x7fff : value * 0x8000;
|
value = value === 1 ? 0x7fff : value * 0x8000;
|
||||||
setInt16(buffer, index, value, littleEndian);
|
setInt16(buffer, index, value, littleEndian);
|
||||||
},
|
},
|
||||||
|
@ -23,19 +23,20 @@ export const SignedFloat: Field<number, never, never> = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InjectScrollControlMessage = struct(
|
export const InjectScrollControlMessage = /* #__PURE__ */ (() =>
|
||||||
{
|
struct(
|
||||||
type: u8,
|
{
|
||||||
pointerX: u32,
|
type: u8(ScrcpyControlMessageType.InjectScroll),
|
||||||
pointerY: u32,
|
pointerX: u32,
|
||||||
screenWidth: u16,
|
pointerY: u32,
|
||||||
screenHeight: u16,
|
screenWidth: u16,
|
||||||
scrollX: SignedFloat,
|
screenHeight: u16,
|
||||||
scrollY: SignedFloat,
|
scrollX: SignedFloat,
|
||||||
buttons: u32,
|
scrollY: SignedFloat,
|
||||||
},
|
buttons: u32,
|
||||||
{ littleEndian: false },
|
},
|
||||||
);
|
{ littleEndian: false },
|
||||||
|
))();
|
||||||
|
|
||||||
export type InjectScrollControlMessage = StructInit<
|
export type InjectScrollControlMessage = StructInit<
|
||||||
typeof InjectScrollControlMessage
|
typeof InjectScrollControlMessage
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
import { omit } from "../../utils/index.js";
|
||||||
|
|
||||||
import type { Init } from "./init.js";
|
import type { Init } from "./init.js";
|
||||||
import { InstanceId } from "./init.js";
|
import { InstanceId } from "./init.js";
|
||||||
import { PrevImpl } from "./prev.js";
|
import { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export const Defaults = /* #__PURE__ */ (() =>
|
export const Defaults = /* #__PURE__ */ (() =>
|
||||||
({
|
({
|
||||||
...PrevImpl.Defaults,
|
...omit(PrevImpl.Defaults, "bitRate", "codecOptions", "encoderName"),
|
||||||
scid: InstanceId.NONE,
|
scid: InstanceId.NONE,
|
||||||
|
|
||||||
videoCodec: "h264",
|
videoCodec: "h264",
|
||||||
|
|
|
@ -6,6 +6,7 @@ export {
|
||||||
serializeInjectTouchControlMessage,
|
serializeInjectTouchControlMessage,
|
||||||
} from "./inject-touch.js";
|
} from "./inject-touch.js";
|
||||||
export * from "./parse-audio-stream-metadata.js";
|
export * from "./parse-audio-stream-metadata.js";
|
||||||
|
export { parseDisplay } from "./parse-display.js";
|
||||||
export { parseEncoder } from "./parse-encoder.js";
|
export { parseEncoder } from "./parse-encoder.js";
|
||||||
export { parseVideoStreamMetadata } from "./parse-video-stream-metadata.js";
|
export { parseVideoStreamMetadata } from "./parse-video-stream-metadata.js";
|
||||||
export { setListDisplays } from "./set-list-display.js";
|
export { setListDisplays } from "./set-list-display.js";
|
||||||
|
|
|
@ -2,25 +2,27 @@ import type { StructInit } from "@yume-chan/struct";
|
||||||
import { struct, u16, u32, u64, u8 } from "@yume-chan/struct";
|
import { struct, u16, u32, u64, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { AndroidMotionEventAction } from "../../android/motion-event.js";
|
import type { AndroidMotionEventAction } from "../../android/motion-event.js";
|
||||||
|
import { ScrcpyControlMessageType } from "../../base/control-message-type.js";
|
||||||
import type { ScrcpyInjectTouchControlMessage } from "../../latest.js";
|
import type { ScrcpyInjectTouchControlMessage } from "../../latest.js";
|
||||||
|
|
||||||
import { PrevImpl } from "./prev.js";
|
import { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export const InjectTouchControlMessage = struct(
|
export const InjectTouchControlMessage = /* #__PURE__ */ (() =>
|
||||||
{
|
struct(
|
||||||
type: u8,
|
{
|
||||||
action: u8<AndroidMotionEventAction>(),
|
type: u8(ScrcpyControlMessageType.InjectTouch),
|
||||||
pointerId: u64,
|
action: u8<AndroidMotionEventAction>(),
|
||||||
pointerX: u32,
|
pointerId: u64,
|
||||||
pointerY: u32,
|
pointerX: u32,
|
||||||
screenWidth: u16,
|
pointerY: u32,
|
||||||
screenHeight: u16,
|
screenWidth: u16,
|
||||||
pressure: PrevImpl.UnsignedFloat,
|
screenHeight: u16,
|
||||||
actionButton: u32,
|
pressure: PrevImpl.UnsignedFloat,
|
||||||
buttons: u32,
|
actionButton: u32,
|
||||||
},
|
buttons: u32,
|
||||||
{ littleEndian: false },
|
},
|
||||||
);
|
{ littleEndian: false },
|
||||||
|
))();
|
||||||
|
|
||||||
export type InjectTouchControlMessage = StructInit<
|
export type InjectTouchControlMessage = StructInit<
|
||||||
typeof InjectTouchControlMessage
|
typeof InjectTouchControlMessage
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import type { ScrcpyDisplay } from "../../base/index.js";
|
import type { ScrcpyDisplay } from "../../base/index.js";
|
||||||
|
|
||||||
export function parseDisplay(line: string): ScrcpyDisplay | undefined {
|
export function parseDisplay(line: string): ScrcpyDisplay | undefined {
|
||||||
|
// The client-side option name is `--display`
|
||||||
|
// but the server-side option name is always `display_id`
|
||||||
const match = line.match(/^\s+--display=(\d+)\s+\(([^)]+)\)$/);
|
const match = line.match(/^\s+--display=(\d+)\s+\(([^)]+)\)$/);
|
||||||
if (match) {
|
if (match) {
|
||||||
const display: ScrcpyDisplay = {
|
const display: ScrcpyDisplay = {
|
||||||
|
|
|
@ -41,7 +41,7 @@ async function parseAsync(
|
||||||
let width: number | undefined;
|
let width: number | undefined;
|
||||||
let height: number | undefined;
|
let height: number | undefined;
|
||||||
if (options.sendCodecMeta) {
|
if (options.sendCodecMeta) {
|
||||||
codec = await PrevImpl.readU32(buffered);
|
codec = (await PrevImpl.readU32(buffered)) as ScrcpyVideoCodecId;
|
||||||
width = await PrevImpl.readU32(buffered);
|
width = await PrevImpl.readU32(buffered);
|
||||||
height = await PrevImpl.readU32(buffered);
|
height = await PrevImpl.readU32(buffered);
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,9 +64,7 @@ export function parseVideoStreamMetadata(
|
||||||
if (!options.sendDeviceMeta && !options.sendCodecMeta) {
|
if (!options.sendDeviceMeta && !options.sendCodecMeta) {
|
||||||
return {
|
return {
|
||||||
stream,
|
stream,
|
||||||
metadata: {
|
metadata: { codec: toCodecId(options.videoCodec) },
|
||||||
codec: toCodecId(options.videoCodec),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export * from "../../2_0/impl/index.js";
|
export * from "../../2_1/impl/index.js";
|
||||||
export { Defaults } from "./defaults.js";
|
export { Defaults } from "./defaults.js";
|
||||||
export type { Init } from "./init.js";
|
export type { Init } from "./init.js";
|
||||||
export { parseDisplay } from "./parse-display.js";
|
export { parseDisplay } from "./parse-display.js";
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import type { PrevImpl } from "./prev.js";
|
import type { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export interface Init extends Omit<PrevImpl.Init, "display"> {
|
export interface Init extends PrevImpl.Init {
|
||||||
videoSource?: "display" | "camera";
|
videoSource?: "display" | "camera";
|
||||||
displayId?: number;
|
|
||||||
cameraId?: string | undefined;
|
cameraId?: string | undefined;
|
||||||
cameraSize?: string | undefined;
|
cameraSize?: string | undefined;
|
||||||
cameraFacing?: "front" | "back" | "external" | undefined;
|
cameraFacing?: "front" | "back" | "external" | undefined;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export * as PrevImpl from "../../2_0/impl/index.js";
|
export * as PrevImpl from "../../2_1/impl/index.js";
|
||||||
|
|
|
@ -54,6 +54,10 @@ export class ScrcpyOptions2_2 implements ScrcpyOptions<Init> {
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
|
if (this.value.videoSource === "camera") {
|
||||||
|
this.value.control = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = new ClipboardStream();
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
this.#ackClipboardHandler = new AckClipboardHandler();
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export * from "../../2_0/impl/index.js";
|
export * from "../../2_2/impl/index.js";
|
||||||
export type { Init } from "./init.js";
|
export type { Init } from "./init.js";
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export * as PrevImpl from "../../2_0/impl/index.js";
|
export * as PrevImpl from "../../2_2/impl/index.js";
|
||||||
|
|
|
@ -54,6 +54,10 @@ export class ScrcpyOptions2_3 implements ScrcpyOptions<Init> {
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
|
if (this.value.videoSource === "camera") {
|
||||||
|
this.value.control = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = new ClipboardStream();
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
this.#ackClipboardHandler = new AckClipboardHandler();
|
||||||
|
|
|
@ -17,6 +17,7 @@ import type {
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
ScrcpySetClipboardControlMessage,
|
ScrcpySetClipboardControlMessage,
|
||||||
ScrcpyUHidCreateControlMessage,
|
ScrcpyUHidCreateControlMessage,
|
||||||
|
ScrcpyUHidOutputDeviceMessage,
|
||||||
} from "../latest.js";
|
} from "../latest.js";
|
||||||
|
|
||||||
import type { Init } from "./impl/index.js";
|
import type { Init } from "./impl/index.js";
|
||||||
|
@ -55,13 +56,19 @@ export class ScrcpyOptions2_4 implements ScrcpyOptions<Init> {
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
#uHidOutput: UHidOutputStream | undefined;
|
#uHidOutput: UHidOutputStream | undefined;
|
||||||
get uHidOutput(): UHidOutputStream | undefined {
|
get uHidOutput():
|
||||||
|
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
||||||
|
| undefined {
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
|
if (this.value.videoSource === "camera") {
|
||||||
|
this.value.control = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.value.control) {
|
if (this.value.control) {
|
||||||
if (this.value.clipboardAutosync) {
|
if (this.value.clipboardAutosync) {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.#clipboard = new ClipboardStream();
|
||||||
|
|
|
@ -17,9 +17,9 @@ import type {
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
ScrcpySetClipboardControlMessage,
|
ScrcpySetClipboardControlMessage,
|
||||||
ScrcpyUHidCreateControlMessage,
|
ScrcpyUHidCreateControlMessage,
|
||||||
|
ScrcpyUHidOutputDeviceMessage,
|
||||||
} from "../latest.js";
|
} from "../latest.js";
|
||||||
|
|
||||||
import type { Init } from "./impl/index.js";
|
|
||||||
import {
|
import {
|
||||||
AckClipboardHandler,
|
AckClipboardHandler,
|
||||||
ClipboardStream,
|
ClipboardStream,
|
||||||
|
@ -37,7 +37,10 @@ import {
|
||||||
serializeUHidCreateControlMessage,
|
serializeUHidCreateControlMessage,
|
||||||
setListDisplays,
|
setListDisplays,
|
||||||
setListEncoders,
|
setListEncoders,
|
||||||
|
UHidOutputStream
|
||||||
|
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
import type {Init} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init>;
|
||||||
|
@ -53,12 +56,27 @@ export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#uHidOutput: UHidOutputStream | undefined;
|
||||||
|
get uHidOutput():
|
||||||
|
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
||||||
|
| undefined {
|
||||||
|
return this.#uHidOutput;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.videoSource === "camera") {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.value.control = false;
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
}
|
||||||
|
|
||||||
|
if (this.value.control) {
|
||||||
|
if (this.value.clipboardAutosync) {
|
||||||
|
this.#clipboard = new ClipboardStream();
|
||||||
|
this.#ackClipboardHandler = new AckClipboardHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#uHidOutput = new UHidOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +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 = struct(
|
export const UHidCreateControlMessage = /* #__PURE__ */ (() =>
|
||||||
{
|
struct(
|
||||||
type: u8,
|
{
|
||||||
id: u16,
|
type: u8(ScrcpyControlMessageType.UHidCreate),
|
||||||
name: string(u8),
|
id: u16,
|
||||||
data: buffer(u16),
|
name: string(u8),
|
||||||
},
|
data: buffer(u16),
|
||||||
{ littleEndian: false },
|
},
|
||||||
);
|
{ littleEndian: false },
|
||||||
|
))();
|
||||||
|
|
||||||
export type UHidCreateControlMessage = StructInit<
|
export type UHidCreateControlMessage = StructInit<
|
||||||
typeof UHidCreateControlMessage
|
typeof UHidCreateControlMessage
|
||||||
|
|
|
@ -17,6 +17,7 @@ import type {
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
ScrcpySetClipboardControlMessage,
|
ScrcpySetClipboardControlMessage,
|
||||||
ScrcpyUHidCreateControlMessage,
|
ScrcpyUHidCreateControlMessage,
|
||||||
|
ScrcpyUHidOutputDeviceMessage,
|
||||||
} from "../latest.js";
|
} from "../latest.js";
|
||||||
|
|
||||||
import type { Init } from "./impl/index.js";
|
import type { Init } from "./impl/index.js";
|
||||||
|
@ -37,6 +38,7 @@ import {
|
||||||
serializeUHidCreateControlMessage,
|
serializeUHidCreateControlMessage,
|
||||||
setListDisplays,
|
setListDisplays,
|
||||||
setListEncoders,
|
setListEncoders,
|
||||||
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
||||||
|
@ -53,12 +55,27 @@ export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#uHidOutput: UHidOutputStream | undefined;
|
||||||
|
get uHidOutput():
|
||||||
|
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
||||||
|
| undefined {
|
||||||
|
return this.#uHidOutput;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.videoSource === "camera") {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.value.control = false;
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
}
|
||||||
|
|
||||||
|
if (this.value.control) {
|
||||||
|
if (this.value.clipboardAutosync) {
|
||||||
|
this.#clipboard = new ClipboardStream();
|
||||||
|
this.#ackClipboardHandler = new AckClipboardHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#uHidOutput = new UHidOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@ import { ScrcpyControlMessageType } from "../../base/index.js";
|
||||||
|
|
||||||
import { PrevImpl } from "./prev.js";
|
import { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export const ControlMessageTypes: readonly ScrcpyControlMessageType[] = [
|
export const ControlMessageTypes: readonly ScrcpyControlMessageType[] =
|
||||||
...PrevImpl.ControlMessageTypes,
|
/* #__PURE__ */ (() => [
|
||||||
ScrcpyControlMessageType.StartApp,
|
...PrevImpl.ControlMessageTypes,
|
||||||
ScrcpyControlMessageType.ResetVideo,
|
ScrcpyControlMessageType.StartApp,
|
||||||
];
|
ScrcpyControlMessageType.ResetVideo,
|
||||||
|
])();
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
|
import { omit } from "../../utils/index.js";
|
||||||
|
|
||||||
import type { Init } from "./init.js";
|
import type { Init } from "./init.js";
|
||||||
import { CaptureOrientation, NewDisplay } from "./init.js";
|
import { CaptureOrientation } from "./init.js";
|
||||||
import { PrevImpl } from "./prev.js";
|
import { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export const Defaults = {
|
export const Defaults = /* #__PURE__ */ (() =>
|
||||||
...PrevImpl.Defaults,
|
({
|
||||||
captureOrientation: CaptureOrientation.Default,
|
...omit(PrevImpl.Defaults, "lockVideoOrientation"),
|
||||||
angle: 0,
|
captureOrientation: CaptureOrientation.Unlocked,
|
||||||
screenOffTimeout: undefined,
|
angle: 0,
|
||||||
listApps: false,
|
screenOffTimeout: undefined,
|
||||||
newDisplay: NewDisplay.Empty,
|
listApps: false,
|
||||||
vdSystemDecorations: true,
|
newDisplay: undefined,
|
||||||
} as const satisfies Required<Init>;
|
vdSystemDecorations: true,
|
||||||
|
}) as const satisfies Required<Init>)();
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
export * from "../../2_7/impl/index.js";
|
export * from "../../2_7/impl/index.js";
|
||||||
export { ControlMessageTypes } from "./control-message-types.js";
|
export { ControlMessageTypes } from "./control-message-types.js";
|
||||||
export { Defaults } from "./defaults.js";
|
export { Defaults } from "./defaults.js";
|
||||||
export type { Init } from "./init.js";
|
export {
|
||||||
export { EncoderRegex } from "./parse-encoder.js";
|
CaptureOrientation,
|
||||||
|
LockOrientation,
|
||||||
|
NewDisplay,
|
||||||
|
Orientation,
|
||||||
|
type Init,
|
||||||
|
} from "./init.js";
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const LockOrientation = {
|
||||||
Unlocked: 0,
|
Unlocked: 0,
|
||||||
LockedInitial: 1,
|
LockedInitial: 1,
|
||||||
LockedValue: 2,
|
LockedValue: 2,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type LockOrientation =
|
export type LockOrientation =
|
||||||
(typeof LockOrientation)[keyof typeof LockOrientation];
|
(typeof LockOrientation)[keyof typeof LockOrientation];
|
||||||
|
@ -16,16 +16,17 @@ export const Orientation = {
|
||||||
Orient90: 90,
|
Orient90: 90,
|
||||||
Orient180: 180,
|
Orient180: 180,
|
||||||
Orient270: 270,
|
Orient270: 270,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type Orientation = (typeof Orientation)[keyof typeof Orientation];
|
export type Orientation = (typeof Orientation)[keyof typeof Orientation];
|
||||||
|
|
||||||
export class CaptureOrientation implements ScrcpyOptionValue {
|
export class CaptureOrientation implements ScrcpyOptionValue {
|
||||||
static Default = /* #__PURE__ */ new CaptureOrientation(
|
static Unlocked = /* #__PURE__ */ (() =>
|
||||||
LockOrientation.Unlocked,
|
new CaptureOrientation(
|
||||||
Orientation.Orient0,
|
LockOrientation.Unlocked,
|
||||||
false,
|
Orientation.Orient0,
|
||||||
);
|
false,
|
||||||
|
))();
|
||||||
|
|
||||||
lock: LockOrientation;
|
lock: LockOrientation;
|
||||||
orientation: Orientation;
|
orientation: Orientation;
|
||||||
|
@ -59,7 +60,7 @@ export class CaptureOrientation implements ScrcpyOptionValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NewDisplay implements ScrcpyOptionValue {
|
export class NewDisplay implements ScrcpyOptionValue {
|
||||||
static Empty = /* #__PURE__ */ new NewDisplay();
|
static Default = /* #__PURE__ */ new NewDisplay();
|
||||||
|
|
||||||
width?: number | undefined;
|
width?: number | undefined;
|
||||||
height?: number | undefined;
|
height?: number | undefined;
|
||||||
|
@ -90,7 +91,7 @@ export class NewDisplay implements ScrcpyOptionValue {
|
||||||
this.height === undefined &&
|
this.height === undefined &&
|
||||||
this.dpi === undefined
|
this.dpi === undefined
|
||||||
) {
|
) {
|
||||||
return undefined;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.width === undefined) {
|
if (this.width === undefined) {
|
||||||
|
@ -112,6 +113,9 @@ export interface Init extends Omit<PrevImpl.Init, "lockVideoOrientation"> {
|
||||||
|
|
||||||
listApps?: boolean;
|
listApps?: boolean;
|
||||||
|
|
||||||
newDisplay?: NewDisplay;
|
// `display_id` and `new_display` can't be specified at the same time
|
||||||
|
// but `serialize` method will exclude options that are same as the default value
|
||||||
|
// so `displayId: 0` will be ignored
|
||||||
|
newDisplay?: NewDisplay | undefined;
|
||||||
vdSystemDecorations?: boolean;
|
vdSystemDecorations?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export const EncoderRegex = /^\s+scrcpy --encoder-name '([^']+)'$/;
|
|
|
@ -1,2 +1,2 @@
|
||||||
export * as ScrcpyOptionsX_XXImpl from "./impl/index.js";
|
export * as ScrcpyOptions3_0Impl from "./impl/index.js";
|
||||||
export * from "./options.js";
|
export * from "./options.js";
|
||||||
|
|
|
@ -17,6 +17,7 @@ import type {
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
ScrcpySetClipboardControlMessage,
|
ScrcpySetClipboardControlMessage,
|
||||||
ScrcpyUHidCreateControlMessage,
|
ScrcpyUHidCreateControlMessage,
|
||||||
|
ScrcpyUHidOutputDeviceMessage,
|
||||||
} from "../latest.js";
|
} from "../latest.js";
|
||||||
|
|
||||||
import type { Init } from "./impl/index.js";
|
import type { Init } from "./impl/index.js";
|
||||||
|
@ -37,9 +38,10 @@ import {
|
||||||
serializeUHidCreateControlMessage,
|
serializeUHidCreateControlMessage,
|
||||||
setListDisplays,
|
setListDisplays,
|
||||||
setListEncoders,
|
setListEncoders,
|
||||||
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptionsX_X implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions3_0 implements ScrcpyOptions<Init> {
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
|
@ -53,12 +55,27 @@ export class ScrcpyOptionsX_X implements ScrcpyOptions<Init> {
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
|
#uHidOutput: UHidOutputStream | undefined;
|
||||||
|
get uHidOutput():
|
||||||
|
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
||||||
|
| undefined {
|
||||||
|
return this.#uHidOutput;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init: Init) {
|
constructor(init: Init) {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init };
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.videoSource === "camera") {
|
||||||
this.#clipboard = new ClipboardStream();
|
this.value.control = false;
|
||||||
this.#ackClipboardHandler = new AckClipboardHandler();
|
}
|
||||||
|
|
||||||
|
if (this.value.control) {
|
||||||
|
if (this.value.clipboardAutosync) {
|
||||||
|
this.#clipboard = new ClipboardStream();
|
||||||
|
this.#ackClipboardHandler = new AckClipboardHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#uHidOutput = new UHidOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const AndroidMotionEventAction = {
|
||||||
HoverExit: 10,
|
HoverExit: 10,
|
||||||
ButtonPress: 11,
|
ButtonPress: 11,
|
||||||
ButtonRelease: 12,
|
ButtonRelease: 12,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type AndroidMotionEventAction =
|
export type AndroidMotionEventAction =
|
||||||
(typeof AndroidMotionEventAction)[keyof typeof AndroidMotionEventAction];
|
(typeof AndroidMotionEventAction)[keyof typeof AndroidMotionEventAction];
|
||||||
|
@ -27,7 +27,7 @@ export const AndroidMotionEventButton = {
|
||||||
Forward: 16,
|
Forward: 16,
|
||||||
StylusPrimary: 32,
|
StylusPrimary: 32,
|
||||||
StylusSecondary: 64,
|
StylusSecondary: 64,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type AndroidMotionEventButton =
|
export type AndroidMotionEventButton =
|
||||||
(typeof AndroidMotionEventButton)[keyof typeof AndroidMotionEventButton];
|
(typeof AndroidMotionEventButton)[keyof typeof AndroidMotionEventButton];
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const ScrcpyControlMessageType = {
|
||||||
OpenHardKeyboardSettings: 15,
|
OpenHardKeyboardSettings: 15,
|
||||||
StartApp: 16,
|
StartApp: 16,
|
||||||
ResetVideo: 17,
|
ResetVideo: 17,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type ScrcpyControlMessageType =
|
export type ScrcpyControlMessageType =
|
||||||
(typeof ScrcpyControlMessageType)[keyof typeof ScrcpyControlMessageType];
|
(typeof ScrcpyControlMessageType)[keyof typeof ScrcpyControlMessageType];
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type {
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
ScrcpySetClipboardControlMessage,
|
ScrcpySetClipboardControlMessage,
|
||||||
ScrcpyUHidCreateControlMessage,
|
ScrcpyUHidCreateControlMessage,
|
||||||
|
ScrcpyUHidOutputDeviceMessage,
|
||||||
} from "../latest.js";
|
} from "../latest.js";
|
||||||
|
|
||||||
import type { ScrcpyAudioStreamMetadata } from "./audio.js";
|
import type { ScrcpyAudioStreamMetadata } from "./audio.js";
|
||||||
|
@ -22,7 +23,11 @@ export interface ScrcpyOptions<T extends object> {
|
||||||
|
|
||||||
value: Required<T>;
|
value: Required<T>;
|
||||||
|
|
||||||
get clipboard(): ReadableStream<string> | undefined;
|
readonly clipboard?: ReadableStream<string> | undefined;
|
||||||
|
|
||||||
|
readonly uHidOutput?:
|
||||||
|
| ReadableStream<ScrcpyUHidOutputDeviceMessage>
|
||||||
|
| undefined;
|
||||||
|
|
||||||
serialize(): string[];
|
serialize(): string[];
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,17 @@ export const ScrcpyVideoCodecId = {
|
||||||
H264: 0x68_32_36_34,
|
H264: 0x68_32_36_34,
|
||||||
H265: 0x68_32_36_35,
|
H265: 0x68_32_36_35,
|
||||||
AV1: 0x00_61_76_31,
|
AV1: 0x00_61_76_31,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export type ScrcpyVideoCodecId =
|
export type ScrcpyVideoCodecId =
|
||||||
(typeof ScrcpyVideoCodecId)[keyof typeof ScrcpyVideoCodecId];
|
(typeof ScrcpyVideoCodecId)[keyof typeof ScrcpyVideoCodecId];
|
||||||
|
|
||||||
|
export const ScrcpyVideoCodecNameMap = /* #__PURE__ */ (() => {
|
||||||
|
const result = new Map<number, string>();
|
||||||
|
for (const key in ScrcpyVideoCodecId) {
|
||||||
|
const value =
|
||||||
|
ScrcpyVideoCodecId[key as keyof typeof ScrcpyVideoCodecId];
|
||||||
|
result.set(value, key);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})();
|
||||||
|
|
|
@ -136,7 +136,7 @@ const ObuType = {
|
||||||
RedundantFrameHeader: 7,
|
RedundantFrameHeader: 7,
|
||||||
TileList: 8,
|
TileList: 8,
|
||||||
Padding: 15,
|
Padding: 15,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
type ObuType = (typeof ObuType)[keyof typeof ObuType];
|
type ObuType = (typeof ObuType)[keyof typeof ObuType];
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ const ColorPrimaries = {
|
||||||
Smpte431: 11,
|
Smpte431: 11,
|
||||||
Smpte432: 12,
|
Smpte432: 12,
|
||||||
Ebu3213: 22,
|
Ebu3213: 22,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
const TransferCharacteristics = {
|
const TransferCharacteristics = {
|
||||||
Bt709: 1,
|
Bt709: 1,
|
||||||
|
@ -173,7 +173,7 @@ const TransferCharacteristics = {
|
||||||
Smpte2084: 16,
|
Smpte2084: 16,
|
||||||
Smpte428: 17,
|
Smpte428: 17,
|
||||||
Hlg: 18,
|
Hlg: 18,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
const MatrixCoefficients = {
|
const MatrixCoefficients = {
|
||||||
Identity: 0,
|
Identity: 0,
|
||||||
|
@ -190,7 +190,7 @@ const MatrixCoefficients = {
|
||||||
ChromatNcl: 12,
|
ChromatNcl: 12,
|
||||||
ChromatCl: 13,
|
ChromatCl: 13,
|
||||||
ICtCp: 14,
|
ICtCp: 14,
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export class Av1 extends BitReader {
|
export class Av1 extends BitReader {
|
||||||
static ObuType = ObuType;
|
static ObuType = ObuType;
|
||||||
|
@ -623,13 +623,16 @@ export class Av1 extends BitReader {
|
||||||
// const NumPlanes = mono_chrome ? 1 : 3;
|
// const NumPlanes = mono_chrome ? 1 : 3;
|
||||||
|
|
||||||
const color_description_present_flag = !!this.f1();
|
const color_description_present_flag = !!this.f1();
|
||||||
let color_primaries = Av1.ColorPrimaries.Unspecified;
|
let color_primaries: Av1.ColorPrimaries =
|
||||||
let transfer_characteristics = Av1.TransferCharacteristics.Unspecified;
|
Av1.ColorPrimaries.Unspecified;
|
||||||
let matrix_coefficients = Av1.MatrixCoefficients.Unspecified;
|
let transfer_characteristics: Av1.TransferCharacteristics =
|
||||||
|
Av1.TransferCharacteristics.Unspecified;
|
||||||
|
let matrix_coefficients: Av1.MatrixCoefficients =
|
||||||
|
Av1.MatrixCoefficients.Unspecified;
|
||||||
if (color_description_present_flag) {
|
if (color_description_present_flag) {
|
||||||
color_primaries = this.f(8);
|
color_primaries = this.f(8) as Av1.ColorPrimaries;
|
||||||
transfer_characteristics = this.f(8);
|
transfer_characteristics = this.f(8) as Av1.TransferCharacteristics;
|
||||||
matrix_coefficients = this.f(8);
|
matrix_coefficients = this.f(8) as Av1.MatrixCoefficients;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color_range = false;
|
let color_range = false;
|
||||||
|
|
|
@ -6,17 +6,19 @@ import type {
|
||||||
AndroidKeyEventAction,
|
AndroidKeyEventAction,
|
||||||
AndroidKeyEventMeta,
|
AndroidKeyEventMeta,
|
||||||
} from "../android/index.js";
|
} from "../android/index.js";
|
||||||
|
import { ScrcpyControlMessageType } from "../base/index.js";
|
||||||
|
|
||||||
export const ScrcpyInjectKeyCodeControlMessage = struct(
|
export const ScrcpyInjectKeyCodeControlMessage = /* #__PURE__ */ (() =>
|
||||||
{
|
struct(
|
||||||
type: u8,
|
{
|
||||||
action: u8<AndroidKeyEventAction>(),
|
type: u8(ScrcpyControlMessageType.InjectKeyCode),
|
||||||
keyCode: u32<AndroidKeyCode>(),
|
action: u8<AndroidKeyEventAction>(),
|
||||||
repeat: u32,
|
keyCode: u32<AndroidKeyCode>(),
|
||||||
metaState: u32<AndroidKeyEventMeta>(),
|
repeat: u32,
|
||||||
},
|
metaState: u32<AndroidKeyEventMeta>(),
|
||||||
{ littleEndian: false },
|
},
|
||||||
);
|
{ littleEndian: false },
|
||||||
|
))();
|
||||||
|
|
||||||
export type ScrcpyInjectKeyCodeControlMessage = StructInit<
|
export type ScrcpyInjectKeyCodeControlMessage = StructInit<
|
||||||
typeof ScrcpyInjectKeyCodeControlMessage
|
typeof ScrcpyInjectKeyCodeControlMessage
|
||||||
|
|
|
@ -24,7 +24,7 @@ export class ScrcpyControlMessageTypeMap {
|
||||||
message: Omit<T, "type">,
|
message: Omit<T, "type">,
|
||||||
type: T["type"],
|
type: T["type"],
|
||||||
): T {
|
): T {
|
||||||
(message as T).type = this.get(type);
|
(message as T).type = this.get(type) as ScrcpyControlMessageType;
|
||||||
return message as T;
|
return message as T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { buffer, struct, u16, u8 } from "@yume-chan/struct";
|
import { buffer, struct, u16, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
export const ScrcpyUHidInputControlMessage = struct(
|
import { ScrcpyControlMessageType } from "../base/index.js";
|
||||||
{
|
|
||||||
type: u8,
|
export const ScrcpyUHidInputControlMessage = /* #__PURE__ */ (() =>
|
||||||
id: u16,
|
struct(
|
||||||
data: buffer(u16),
|
{
|
||||||
},
|
type: u8(ScrcpyControlMessageType.UHidInput),
|
||||||
{ littleEndian: false },
|
id: u16,
|
||||||
);
|
data: buffer(u16),
|
||||||
|
},
|
||||||
|
{ littleEndian: false },
|
||||||
|
))();
|
||||||
|
|
||||||
export type ScrcpyUHidInputControlMessage = StructInit<
|
export type ScrcpyUHidInputControlMessage = StructInit<
|
||||||
typeof ScrcpyUHidInputControlMessage
|
typeof ScrcpyUHidInputControlMessage
|
||||||
|
|
|
@ -10,10 +10,12 @@ import type {
|
||||||
ScrcpyInjectScrollControlMessage,
|
ScrcpyInjectScrollControlMessage,
|
||||||
ScrcpyInjectTouchControlMessage,
|
ScrcpyInjectTouchControlMessage,
|
||||||
ScrcpySetClipboardControlMessage,
|
ScrcpySetClipboardControlMessage,
|
||||||
|
ScrcpyUHidCreateControlMessage,
|
||||||
} from "../latest.js";
|
} from "../latest.js";
|
||||||
|
|
||||||
import type { ScrcpyInjectKeyCodeControlMessage } from "./inject-key-code.js";
|
import type { ScrcpyInjectKeyCodeControlMessage } from "./inject-key-code.js";
|
||||||
import { ScrcpyControlMessageSerializer } from "./serializer.js";
|
import { ScrcpyControlMessageSerializer } from "./serializer.js";
|
||||||
|
import type { ScrcpyUHidInputControlMessage } from "./uhid.js";
|
||||||
|
|
||||||
export class ScrcpyControlMessageWriter {
|
export class ScrcpyControlMessageWriter {
|
||||||
#writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
|
#writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
|
||||||
|
@ -27,25 +29,23 @@ export class ScrcpyControlMessageWriter {
|
||||||
this.#serializer = new ScrcpyControlMessageSerializer(options);
|
this.#serializer = new ScrcpyControlMessageSerializer(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async write(message: Uint8Array) {
|
write(message: Uint8Array) {
|
||||||
await Consumable.WritableStream.write(this.#writer, message);
|
return Consumable.WritableStream.write(this.#writer, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async injectKeyCode(
|
injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">) {
|
||||||
message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">,
|
return this.write(this.#serializer.injectKeyCode(message));
|
||||||
) {
|
|
||||||
await this.write(this.#serializer.injectKeyCode(message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async injectText(text: string) {
|
injectText(text: string) {
|
||||||
await this.write(this.#serializer.injectText(text));
|
return this.write(this.#serializer.injectText(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `pressure` is a float value between 0 and 1.
|
* `pressure` is a float value between 0 and 1.
|
||||||
*/
|
*/
|
||||||
async injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
|
injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
|
||||||
await this.write(this.#serializer.injectTouch(message));
|
return this.write(this.#serializer.injectTouch(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,24 +67,24 @@ export class ScrcpyControlMessageWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setScreenPowerMode(mode: AndroidScreenPowerMode) {
|
setScreenPowerMode(mode: AndroidScreenPowerMode) {
|
||||||
await this.write(this.#serializer.setDisplayPower(mode));
|
return this.write(this.#serializer.setDisplayPower(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
async expandNotificationPanel() {
|
expandNotificationPanel() {
|
||||||
await this.write(this.#serializer.expandNotificationPanel());
|
return this.write(this.#serializer.expandNotificationPanel());
|
||||||
}
|
}
|
||||||
|
|
||||||
async expandSettingPanel() {
|
expandSettingPanel() {
|
||||||
await this.write(this.#serializer.expandSettingPanel());
|
return this.write(this.#serializer.expandSettingPanel());
|
||||||
}
|
}
|
||||||
|
|
||||||
async collapseNotificationPanel() {
|
collapseNotificationPanel() {
|
||||||
await this.write(this.#serializer.collapseNotificationPanel());
|
return this.write(this.#serializer.collapseNotificationPanel());
|
||||||
}
|
}
|
||||||
|
|
||||||
async rotateDevice() {
|
rotateDevice() {
|
||||||
await this.write(this.#serializer.rotateDevice());
|
return this.write(this.#serializer.rotateDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
async setClipboard(
|
async setClipboard(
|
||||||
|
@ -99,6 +99,29 @@ export class ScrcpyControlMessageWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uHidCreate(message: Omit<ScrcpyUHidCreateControlMessage, "type">) {
|
||||||
|
return this.write(this.#serializer.uHidCreate(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
uHidInput(message: Omit<ScrcpyUHidInputControlMessage, "type">) {
|
||||||
|
return this.write(this.#serializer.uHidInput(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
uHidDestroy(id: number) {
|
||||||
|
return this.write(this.#serializer.uHidDestroy(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
startApp(
|
||||||
|
name: string,
|
||||||
|
options?: { forceStop?: boolean; searchByName?: boolean },
|
||||||
|
) {
|
||||||
|
return this.write(this.#serializer.startApp(name, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
resetVideo() {
|
||||||
|
return this.write(this.#serializer.resetVideo());
|
||||||
|
}
|
||||||
|
|
||||||
releaseLock() {
|
releaseLock() {
|
||||||
this.#writer.releaseLock();
|
this.#writer.releaseLock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ export * from "./2_4/index.js";
|
||||||
export * from "./2_5.js";
|
export * from "./2_5.js";
|
||||||
export * from "./2_6/index.js";
|
export * from "./2_6/index.js";
|
||||||
export * from "./2_7/index.js";
|
export * from "./2_7/index.js";
|
||||||
|
export * from "./3_0/index.js";
|
||||||
export * from "./android/index.js";
|
export * from "./android/index.js";
|
||||||
export * from "./base/index.js";
|
export * from "./base/index.js";
|
||||||
export * from "./codec/index.js";
|
export * from "./codec/index.js";
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
export {
|
export {
|
||||||
BackOrScreenOnControlMessage as ScrcpyBackOrScreenOnControlMessage,
|
BackOrScreenOnControlMessage as ScrcpyBackOrScreenOnControlMessage,
|
||||||
|
CaptureOrientation as ScrcpyCaptureOrientation,
|
||||||
|
CodecOptions as ScrcpyCodecOptions,
|
||||||
InjectScrollControlMessage as ScrcpyInjectScrollControlMessage,
|
InjectScrollControlMessage as ScrcpyInjectScrollControlMessage,
|
||||||
InjectTouchControlMessage as ScrcpyInjectTouchControlMessage,
|
InjectTouchControlMessage as ScrcpyInjectTouchControlMessage,
|
||||||
InstanceId as ScrcpyInstanceId,
|
InstanceId as ScrcpyInstanceId,
|
||||||
|
LockOrientation as ScrcpyLockOrientation,
|
||||||
|
NewDisplay as ScrcpyNewDisplay,
|
||||||
|
Orientation as ScrcpyOrientation,
|
||||||
|
PointerId as ScrcpyPointerId,
|
||||||
SetClipboardControlMessage as ScrcpySetClipboardControlMessage,
|
SetClipboardControlMessage as ScrcpySetClipboardControlMessage,
|
||||||
UHidCreateControlMessage as ScrcpyUHidCreateControlMessage,
|
UHidCreateControlMessage as ScrcpyUHidCreateControlMessage,
|
||||||
} from "./2_7/impl/index.js";
|
UHidOutputDeviceMessage as ScrcpyUHidOutputDeviceMessage,
|
||||||
|
} from "./3_0/impl/index.js";
|
||||||
|
|
11
libraries/scrcpy/src/utils/clamp.ts
Normal file
11
libraries/scrcpy/src/utils/clamp.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export function clamp(value: number, min: number, max: number): number {
|
||||||
|
if (value < min) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
|
@ -1,2 +1,4 @@
|
||||||
|
export * from "./clamp.js";
|
||||||
export * from "./constants.js";
|
export * from "./constants.js";
|
||||||
|
export * from "./omit.js";
|
||||||
export * from "./wrapper.js";
|
export * from "./wrapper.js";
|
||||||
|
|
11
libraries/scrcpy/src/utils/omit.ts
Normal file
11
libraries/scrcpy/src/utils/omit.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
|
export function omit<T extends Record<string, unknown>, K extends (keyof T)[]>(
|
||||||
|
value: T,
|
||||||
|
...keys: K
|
||||||
|
): T {
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(value).filter(
|
||||||
|
([key]) => !keys.includes(key as K[number]),
|
||||||
|
),
|
||||||
|
) as never;
|
||||||
|
}
|
|
@ -32,6 +32,10 @@ export class ScrcpyOptionsWrapper<T extends object>
|
||||||
return this.#base.clipboard;
|
return this.#base.clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get uHidOutput() {
|
||||||
|
return this.#base.uHidOutput;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(options: ScrcpyOptions<T>) {
|
constructor(options: ScrcpyOptions<T>) {
|
||||||
this.#base = options;
|
this.#base = options;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import type {
|
import type {
|
||||||
AbortSignal,
|
AbortSignal,
|
||||||
|
ReadableStreamIteratorOptions,
|
||||||
ReadableStream as ReadableStreamType,
|
ReadableStream as ReadableStreamType,
|
||||||
TransformStream as TransformStreamType,
|
TransformStream as TransformStreamType,
|
||||||
WritableStream as WritableStreamType,
|
WritableStream as WritableStreamType,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
|
|
||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
|
export { ReadableStream };
|
||||||
|
|
||||||
/** A controller object that allows you to abort one or more DOM requests as and when desired. */
|
/** A controller object that allows you to abort one or more DOM requests as and when desired. */
|
||||||
export interface AbortController {
|
export interface AbortController {
|
||||||
|
@ -32,13 +34,70 @@ interface GlobalExtension {
|
||||||
TransformStream: typeof TransformStreamType;
|
TransformStream: typeof TransformStreamType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const { AbortController } = globalThis as unknown as GlobalExtension;
|
||||||
|
|
||||||
export type ReadableStream<T> = ReadableStreamType<T>;
|
export type ReadableStream<T> = ReadableStreamType<T>;
|
||||||
export type WritableStream<T> = WritableStreamType<T>;
|
export type WritableStream<T> = WritableStreamType<T>;
|
||||||
export type TransformStream<I, O> = TransformStreamType<I, O>;
|
export type TransformStream<I, O> = TransformStreamType<I, O>;
|
||||||
|
|
||||||
export const {
|
const ReadableStream = /* #__PURE__ */ (() => {
|
||||||
AbortController,
|
const { ReadableStream } = globalThis as unknown as GlobalExtension;
|
||||||
ReadableStream,
|
|
||||||
WritableStream,
|
if (!ReadableStream.from) {
|
||||||
TransformStream,
|
ReadableStream.from = function (iterable) {
|
||||||
} = globalThis as unknown as GlobalExtension;
|
const iterator =
|
||||||
|
Symbol.asyncIterator in iterable
|
||||||
|
? iterable[Symbol.asyncIterator]()
|
||||||
|
: iterable[Symbol.iterator]();
|
||||||
|
|
||||||
|
return new ReadableStream({
|
||||||
|
async pull(controller) {
|
||||||
|
const result = await iterator.next();
|
||||||
|
if (result.done) {
|
||||||
|
controller.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller.enqueue(result.value);
|
||||||
|
},
|
||||||
|
async cancel(reason) {
|
||||||
|
await iterator.return?.(reason);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!ReadableStream.prototype[Symbol.asyncIterator] ||
|
||||||
|
!ReadableStream.prototype.values
|
||||||
|
) {
|
||||||
|
ReadableStream.prototype.values = async function* <R>(
|
||||||
|
this: ReadableStream<R>,
|
||||||
|
options?: ReadableStreamIteratorOptions,
|
||||||
|
) {
|
||||||
|
const reader = this.getReader();
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
yield value;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (!options?.preventCancel) {
|
||||||
|
await reader.cancel();
|
||||||
|
}
|
||||||
|
reader.releaseLock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ReadableStream.prototype[Symbol.asyncIterator] =
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
ReadableStream.prototype.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadableStream;
|
||||||
|
})();
|
||||||
|
|
||||||
|
export const { WritableStream, TransformStream } =
|
||||||
|
globalThis as unknown as GlobalExtension;
|
||||||
|
|
|
@ -242,7 +242,7 @@ export declare class ReadableStream<out R> implements AsyncIterable<R> {
|
||||||
* such as an array, an async generator, or a Node.js readable stream.
|
* such as an array, an async generator, or a Node.js readable stream.
|
||||||
*/
|
*/
|
||||||
static from<R>(
|
static from<R>(
|
||||||
asyncIterable: Iterable<R> | AsyncIterable<R> | ReadableStreamLike<R>,
|
asyncIterable: Iterable<R> | AsyncIterable<R>,
|
||||||
): ReadableStream<R>;
|
): ReadableStream<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ export declare class ReadableStream<out R> implements AsyncIterable<R> {
|
||||||
*/
|
*/
|
||||||
export declare interface ReadableStreamAsyncIterator<R>
|
export declare interface ReadableStreamAsyncIterator<R>
|
||||||
extends AsyncIterableIterator<R> {
|
extends AsyncIterableIterator<R> {
|
||||||
next(): Promise<IteratorResult<R, undefined>>;
|
next(): Promise<IteratorResult<R, void>>;
|
||||||
return(value?: R): Promise<IteratorResult<R>>;
|
return(value?: R): Promise<IteratorResult<R>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,7 @@ export interface BufferLike {
|
||||||
|
|
||||||
export const EmptyUint8Array = new Uint8Array(0);
|
export const EmptyUint8Array = new Uint8Array(0);
|
||||||
|
|
||||||
// Rollup doesn't support `/* #__NO_SIDE_EFFECTS__ */ export const a = () => {}
|
export const buffer: BufferLike = function (
|
||||||
/* #__NO_SIDE_EFFECTS__ */
|
|
||||||
function _buffer(
|
|
||||||
lengthOrField:
|
lengthOrField:
|
||||||
| string
|
| string
|
||||||
| number
|
| number
|
||||||
|
@ -259,6 +257,4 @@ function _buffer(
|
||||||
return reader.readExactly(length);
|
return reader.readExactly(length);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
} as never;
|
||||||
|
|
||||||
export const buffer: BufferLike = _buffer as never;
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ import { bipedal } from "./bipedal.js";
|
||||||
import type { Field } from "./field.js";
|
import type { Field } from "./field.js";
|
||||||
|
|
||||||
export interface NumberField<T> extends Field<T, never, never> {
|
export interface NumberField<T> extends Field<T, never, never> {
|
||||||
<U>(infer?: T): Field<U, never, never>;
|
<const U>(infer?: U): Field<U, never, never>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #__NO_SIDE_EFFECTS__ */
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
function number<T>(
|
function factory<T>(
|
||||||
size: number,
|
size: number,
|
||||||
serialize: Field<T, never, never>["serialize"],
|
serialize: Field<T, never, never>["serialize"],
|
||||||
deserialize: Field<T, never, never>["deserialize"],
|
deserialize: Field<T, never, never>["deserialize"],
|
||||||
|
@ -34,7 +34,7 @@ function number<T>(
|
||||||
return result as never;
|
return result as never;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const u8 = number<number>(
|
export const u8 = factory<number>(
|
||||||
1,
|
1,
|
||||||
(value, { buffer, index }) => {
|
(value, { buffer, index }) => {
|
||||||
buffer[index] = value;
|
buffer[index] = value;
|
||||||
|
@ -45,7 +45,7 @@ export const u8 = number<number>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const s8 = number<number>(
|
export const s8 = factory<number>(
|
||||||
1,
|
1,
|
||||||
(value, { buffer, index }) => {
|
(value, { buffer, index }) => {
|
||||||
buffer[index] = value;
|
buffer[index] = value;
|
||||||
|
@ -56,7 +56,7 @@ export const s8 = number<number>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const u16 = number<number>(
|
export const u16 = factory<number>(
|
||||||
2,
|
2,
|
||||||
(value, { buffer, index, littleEndian }) => {
|
(value, { buffer, index, littleEndian }) => {
|
||||||
setUint16(buffer, index, value, littleEndian);
|
setUint16(buffer, index, value, littleEndian);
|
||||||
|
@ -67,7 +67,7 @@ export const u16 = number<number>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const s16 = number<number>(
|
export const s16 = factory<number>(
|
||||||
2,
|
2,
|
||||||
(value, { buffer, index, littleEndian }) => {
|
(value, { buffer, index, littleEndian }) => {
|
||||||
setInt16(buffer, index, value, littleEndian);
|
setInt16(buffer, index, value, littleEndian);
|
||||||
|
@ -78,7 +78,7 @@ export const s16 = number<number>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const u32 = number<number>(
|
export const u32 = factory<number>(
|
||||||
4,
|
4,
|
||||||
(value, { buffer, index, littleEndian }) => {
|
(value, { buffer, index, littleEndian }) => {
|
||||||
setUint32(buffer, index, value, littleEndian);
|
setUint32(buffer, index, value, littleEndian);
|
||||||
|
@ -89,7 +89,7 @@ export const u32 = number<number>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const s32 = number<number>(
|
export const s32 = factory<number>(
|
||||||
4,
|
4,
|
||||||
(value, { buffer, index, littleEndian }) => {
|
(value, { buffer, index, littleEndian }) => {
|
||||||
setInt32(buffer, index, value, littleEndian);
|
setInt32(buffer, index, value, littleEndian);
|
||||||
|
@ -100,7 +100,7 @@ export const s32 = number<number>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const u64 = number<bigint>(
|
export const u64 = factory<bigint>(
|
||||||
8,
|
8,
|
||||||
(value, { buffer, index, littleEndian }) => {
|
(value, { buffer, index, littleEndian }) => {
|
||||||
setUint64(buffer, index, value, littleEndian);
|
setUint64(buffer, index, value, littleEndian);
|
||||||
|
@ -111,7 +111,7 @@ export const u64 = number<bigint>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const s64 = number<bigint>(
|
export const s64 = factory<bigint>(
|
||||||
8,
|
8,
|
||||||
(value, { buffer, index, littleEndian }) => {
|
(value, { buffer, index, littleEndian }) => {
|
||||||
setInt64(buffer, index, value, littleEndian);
|
setInt64(buffer, index, value, littleEndian);
|
||||||
|
|
|
@ -33,6 +33,7 @@ export function encodeUtf8(input: string): Uint8Array {
|
||||||
return SharedEncoder.encode(input);
|
return SharedEncoder.encode(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
export function decodeUtf8(buffer: ArrayBufferView | ArrayBuffer): string {
|
export function decodeUtf8(buffer: ArrayBufferView | ArrayBuffer): string {
|
||||||
// `TextDecoder` has internal states in stream mode,
|
// `TextDecoder` has internal states in stream mode,
|
||||||
// but this method is not for stream mode, so the instance can be reused
|
// but this method is not for stream mode, so the instance can be reused
|
||||||
|
|
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
|
@ -439,21 +439,6 @@ importers:
|
||||||
specifier: ^5.6.3
|
specifier: ^5.6.3
|
||||||
version: 5.6.3
|
version: 5.6.3
|
||||||
|
|
||||||
libraries/scrcpy/side-effect-test:
|
|
||||||
devDependencies:
|
|
||||||
'@rollup/plugin-node-resolve':
|
|
||||||
specifier: ^15.3.0
|
|
||||||
version: 15.3.0(rollup@4.27.4)
|
|
||||||
'@rollup/plugin-terser':
|
|
||||||
specifier: ^0.4.4
|
|
||||||
version: 0.4.4(rollup@4.27.4)
|
|
||||||
'@rollup/plugin-typescript':
|
|
||||||
specifier: ^12.1.1
|
|
||||||
version: 12.1.1(rollup@4.27.4)(tslib@2.8.1)(typescript@5.6.3)
|
|
||||||
rollup:
|
|
||||||
specifier: ^4.27.4
|
|
||||||
version: 4.27.4
|
|
||||||
|
|
||||||
libraries/stream-extra:
|
libraries/stream-extra:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@yume-chan/async':
|
'@yume-chan/async':
|
||||||
|
@ -544,6 +529,31 @@ importers:
|
||||||
specifier: ^2.2.3
|
specifier: ^2.2.3
|
||||||
version: 2.2.3
|
version: 2.2.3
|
||||||
|
|
||||||
|
toolchain/side-effect-test:
|
||||||
|
dependencies:
|
||||||
|
'@yume-chan/adb':
|
||||||
|
specifier: workspace:^
|
||||||
|
version: link:../../libraries/adb
|
||||||
|
'@yume-chan/struct':
|
||||||
|
specifier: workspace:^
|
||||||
|
version: link:../../libraries/struct
|
||||||
|
devDependencies:
|
||||||
|
'@rollup/plugin-node-resolve':
|
||||||
|
specifier: ^15.3.0
|
||||||
|
version: 15.3.0(rollup@4.27.4)
|
||||||
|
'@rollup/plugin-terser':
|
||||||
|
specifier: ^0.4.4
|
||||||
|
version: 0.4.4(rollup@4.27.4)
|
||||||
|
'@rollup/plugin-typescript':
|
||||||
|
specifier: ^12.1.1
|
||||||
|
version: 12.1.1(rollup@4.27.4)(tslib@2.8.1)(typescript@5.6.3)
|
||||||
|
rollup:
|
||||||
|
specifier: ^4.27.4
|
||||||
|
version: 4.27.4
|
||||||
|
tslib:
|
||||||
|
specifier: ^2.8.1
|
||||||
|
version: 2.8.1
|
||||||
|
|
||||||
toolchain/test-runner:
|
toolchain/test-runner:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
|
|
|
@ -14,6 +14,11 @@
|
||||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^12.1.1",
|
"@rollup/plugin-typescript": "^12.1.1",
|
||||||
"rollup": "^4.27.4"
|
"rollup": "^4.27.4",
|
||||||
|
"tslib": "^2.8.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@yume-chan/adb": "workspace:^",
|
||||||
|
"@yume-chan/struct": "workspace:^"
|
||||||
}
|
}
|
||||||
}
|
}
|
33
toolchain/side-effect-test/src/index.js
Normal file
33
toolchain/side-effect-test/src/index.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import {
|
||||||
|
bipedal,
|
||||||
|
buffer,
|
||||||
|
decodeUtf8,
|
||||||
|
encodeUtf8,
|
||||||
|
s16,
|
||||||
|
s32,
|
||||||
|
s64,
|
||||||
|
s8,
|
||||||
|
string,
|
||||||
|
struct,
|
||||||
|
u16,
|
||||||
|
u32,
|
||||||
|
u64,
|
||||||
|
u8,
|
||||||
|
} from "@yume-chan/struct";
|
||||||
|
|
||||||
|
bipedal(function () {});
|
||||||
|
buffer(u8);
|
||||||
|
decodeUtf8(new Uint8Array());
|
||||||
|
encodeUtf8("");
|
||||||
|
s16(1);
|
||||||
|
s32(1);
|
||||||
|
s64(1);
|
||||||
|
s8(1);
|
||||||
|
string(1);
|
||||||
|
u16(1);
|
||||||
|
u32(1);
|
||||||
|
u64(1);
|
||||||
|
u8(1);
|
||||||
|
struct({}, {});
|
||||||
|
|
||||||
|
export * from "@yume-chan/struct";
|
Loading…
Add table
Add a link
Reference in a new issue