Loading .vscode/settings.json +3 −1 Original line number Diff line number Diff line Loading @@ -68,5 +68,7 @@ "url": "https://developer.microsoft.com/json-schemas/rush/v5/version-policies.schema.json" } ], "typescript.preferences.quoteStyle": "single" "typescript.preferences.quoteStyle": "single", "typescript.format.semicolons": "insert", "editor.formatOnSave": true } apps/demo/src/pages/scrcpy.tsx +39 −18 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ import { CSSProperties, ReactNode, useEffect, useState } from "react"; import { ADB_SYNC_MAX_PACKET_SIZE } from '@yume-chan/adb'; import { EventEmitter } from "@yume-chan/event"; import { AdbScrcpyClient, AdbScrcpyOptions1_22, AndroidKeyCode, AndroidKeyEventAction, AndroidMotionEventAction, CodecOptions, DEFAULT_SERVER_PATH, ScrcpyLogLevel, ScrcpyOptions1_24, ScrcpyVideoOrientation, TinyH264Decoder, WebCodecsDecoder, type H264Decoder, type H264DecoderConstructor, type VideoStreamPacket } from "@yume-chan/scrcpy"; import { AdbScrcpyClient, AdbScrcpyOptions1_22, AndroidKeyCode, AndroidKeyEventAction, AndroidMotionEventAction, CodecOptions, DEFAULT_SERVER_PATH, ScrcpyControlMessage, ScrcpyControlMessageType, ScrcpyLogLevel, ScrcpyOptions1_24, ScrcpyVideoOrientation, TinyH264Decoder, WebCodecsDecoder, type H264Decoder, type H264DecoderConstructor, type VideoStreamPacket } from "@yume-chan/scrcpy"; import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version'; import { ChunkStream, InspectStream, ReadableStream, WritableStream } from '@yume-chan/stream-extra'; Loading Loading @@ -243,6 +243,7 @@ class ScrcpyPageState { get rotatedHeight() { return state.rotate & 1 ? state.width : state.height; } client: AdbScrcpyClient | undefined = undefined; controlMessageWriter: WritableStreamDefaultWriter<ScrcpyControlMessage> | undefined = undefined; async pushServer() { const serverBuffer = await fetchServer(); Loading Loading @@ -363,7 +364,7 @@ class ScrcpyPageState { iconProps: { iconName: Icons.Orientation }, iconOnly: true, text: 'Rotate Device', onClick: () => { this.client!.control!.rotateDevice(); }, onClick: () => { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.RotateDevice }); }, }); result.push({ Loading Loading @@ -792,12 +793,15 @@ class ScrcpyPageState { client.exit.then(this.dispose); client.control!.onClipboardChange(content => { window.navigator.clipboard.writeText(content); }); client.deviceMessageStream!.pipeTo(new WritableStream({ write(message) { window.navigator.clipboard.writeText(message.content); } })).catch(() => { }); runInAction(() => { this.client = client; this.controlMessageWriter = client.controlMessageStream!.getWriter(); this.running = true; }); } catch (e: any) { Loading Loading @@ -846,7 +850,10 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.client.control!.pressBackOrTurnOnScreen(AndroidKeyEventAction.Down); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Down, }); }; handleBackPointerUp = (e: React.PointerEvent<HTMLDivElement>) => { Loading @@ -858,10 +865,13 @@ class ScrcpyPageState { return; } this.client.control!.pressBackOrTurnOnScreen(AndroidKeyEventAction.Up); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Up, }); }; handleHomePointerDown = async (e: React.PointerEvent<HTMLDivElement>) => { handleHomePointerDown = (e: React.PointerEvent<HTMLDivElement>) => { if (!this.client) { return; } Loading @@ -871,7 +881,8 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -879,7 +890,7 @@ class ScrcpyPageState { }); }; handleHomePointerUp = async (e: React.PointerEvent<HTMLDivElement>) => { handleHomePointerUp = (e: React.PointerEvent<HTMLDivElement>) => { if (!this.client) { return; } Loading @@ -888,7 +899,8 @@ class ScrcpyPageState { return; } await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -906,7 +918,8 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading @@ -923,7 +936,8 @@ class ScrcpyPageState { return; } await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading Loading @@ -967,7 +981,8 @@ class ScrcpyPageState { } const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.client.control!.injectTouch({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectTouch, action, pointerId: e.pointerType === "mouse" ? BigInt(-1) : BigInt(e.pointerId), screenWidth: this.client!.screenWidth!, Loading Loading @@ -1006,7 +1021,8 @@ class ScrcpyPageState { e.stopPropagation(); const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.client.control!.injectScroll({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectScroll, screenWidth: this.client!.screenWidth!, screenHeight: this.client!.screenHeight!, pointerX: x, Loading @@ -1028,7 +1044,10 @@ class ScrcpyPageState { const { key, code } = e; if (key.match(/^[!-`{-~]$/i)) { this.client.control!.injectText(key); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectText, text: key, }); return; } Loading @@ -1039,13 +1058,15 @@ class ScrcpyPageState { } as Record<string, AndroidKeyCode | undefined>)[code]; if (keyCode) { await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Down, keyCode, metaState: 0, repeat: 0, }); await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Up, keyCode, metaState: 0, Loading libraries/adb/src/commands/sync/sync.ts +0 −1 Original line number Diff line number Diff line Loading @@ -177,7 +177,6 @@ export class AdbSync extends AutoDisposable { public override async dispose() { super.dispose(); await this.stream.close(); await this.writer.close(); } } libraries/scrcpy/src/adb/client.ts +13 −8 Original line number Diff line number Diff line import { Adb, AdbSubprocessNoneProtocol, AdbSubprocessProtocol, AdbSync } from '@yume-chan/adb'; import { DecodeUtf8Stream, InspectStream, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { DecodeUtf8Stream, InspectStream, pipeFrom, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { ScrcpyControlClient } from '../control/index.js'; import { DEFAULT_SERVER_PATH, VideoStreamPacket } from '../options/index.js'; import { ScrcpyControlMessageSerializeStream, type ScrcpyControlMessage } from '../control/index.js'; import { ScrcpyDeviceMessageDeserializeStream, type ScrcpyDeviceMessage } from '../device-message/index.js'; import { DEFAULT_SERVER_PATH, type VideoStreamPacket } from '../options/index.js'; import type { AdbScrcpyOptions } from './options/index.js'; class ArrayToStream<T> extends ReadableStream<T>{ Loading Loading @@ -68,7 +69,7 @@ export class AdbScrcpyClient { ) { let sync!: AdbSync; return new WrapWritableStream<Uint8Array>({ start: async () => { async start() { sync = await adb.sync(); return sync.write(path); }, Loading Loading @@ -101,7 +102,7 @@ export class AdbScrcpyClient { ...options.formatServerArguments(), ], { // Scrcpy server doesn't split stdout and stderr, // Scrcpy server doesn't use stderr, // so disable Shell Protocol to simplify processing protocols: [AdbSubprocessNoneProtocol], } Loading Loading @@ -254,8 +255,11 @@ export class AdbScrcpyClient { private _videoStream: ReadableStream<VideoStreamPacket>; public get videoStream() { return this._videoStream; } private _control: ScrcpyControlClient | undefined; public get control() { return this._control; } private _controlMessageStream: WritableStream<ScrcpyControlMessage> | undefined; public get controlMessageStream() { return this._controlMessageStream; } private _deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined; public get deviceMessageStream() { return this._deviceMessageStream; } public constructor( options: AdbScrcpyOptions<any>, Loading @@ -277,7 +281,8 @@ export class AdbScrcpyClient { })); if (controlStream) { this._control = new ScrcpyControlClient(options, controlStream); this._controlMessageStream = pipeFrom(controlStream.writable, new ScrcpyControlMessageSerializeStream(options)); this._deviceMessageStream = controlStream.readable.pipeThrough(new ScrcpyDeviceMessageDeserializeStream()); } } Loading libraries/scrcpy/src/adb/connection.ts +4 −8 Original line number Diff line number Diff line Loading @@ -36,8 +36,8 @@ export abstract class AdbScrcpyConnection implements Disposable { } export class AdbScrcpyForwardConnection extends AdbScrcpyConnection { private async connect(): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { return await this.adb.createSocket('localabstract:scrcpy'); private connect(): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { return this.adb.createSocket('localabstract:scrcpy'); } private async connectAndRetry(): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { Loading Loading @@ -94,12 +94,8 @@ export class AdbScrcpyReverseConnection extends AdbScrcpyConnection { private address!: string; public override async initialize(): Promise<void> { try { // try to unbind first await this.adb.reverse.remove('localabstract:scrcpy'); } catch { // ignore error } // try to unbind first, ignore errors await this.adb.reverse.remove('localabstract:scrcpy').catch(() => { }); const queue = new TransformStream<ReadableWritablePair<Uint8Array, Uint8Array>>(); this.streams = queue.readable.getReader(); Loading Loading
.vscode/settings.json +3 −1 Original line number Diff line number Diff line Loading @@ -68,5 +68,7 @@ "url": "https://developer.microsoft.com/json-schemas/rush/v5/version-policies.schema.json" } ], "typescript.preferences.quoteStyle": "single" "typescript.preferences.quoteStyle": "single", "typescript.format.semicolons": "insert", "editor.formatOnSave": true }
apps/demo/src/pages/scrcpy.tsx +39 −18 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ import { CSSProperties, ReactNode, useEffect, useState } from "react"; import { ADB_SYNC_MAX_PACKET_SIZE } from '@yume-chan/adb'; import { EventEmitter } from "@yume-chan/event"; import { AdbScrcpyClient, AdbScrcpyOptions1_22, AndroidKeyCode, AndroidKeyEventAction, AndroidMotionEventAction, CodecOptions, DEFAULT_SERVER_PATH, ScrcpyLogLevel, ScrcpyOptions1_24, ScrcpyVideoOrientation, TinyH264Decoder, WebCodecsDecoder, type H264Decoder, type H264DecoderConstructor, type VideoStreamPacket } from "@yume-chan/scrcpy"; import { AdbScrcpyClient, AdbScrcpyOptions1_22, AndroidKeyCode, AndroidKeyEventAction, AndroidMotionEventAction, CodecOptions, DEFAULT_SERVER_PATH, ScrcpyControlMessage, ScrcpyControlMessageType, ScrcpyLogLevel, ScrcpyOptions1_24, ScrcpyVideoOrientation, TinyH264Decoder, WebCodecsDecoder, type H264Decoder, type H264DecoderConstructor, type VideoStreamPacket } from "@yume-chan/scrcpy"; import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version'; import { ChunkStream, InspectStream, ReadableStream, WritableStream } from '@yume-chan/stream-extra'; Loading Loading @@ -243,6 +243,7 @@ class ScrcpyPageState { get rotatedHeight() { return state.rotate & 1 ? state.width : state.height; } client: AdbScrcpyClient | undefined = undefined; controlMessageWriter: WritableStreamDefaultWriter<ScrcpyControlMessage> | undefined = undefined; async pushServer() { const serverBuffer = await fetchServer(); Loading Loading @@ -363,7 +364,7 @@ class ScrcpyPageState { iconProps: { iconName: Icons.Orientation }, iconOnly: true, text: 'Rotate Device', onClick: () => { this.client!.control!.rotateDevice(); }, onClick: () => { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.RotateDevice }); }, }); result.push({ Loading Loading @@ -792,12 +793,15 @@ class ScrcpyPageState { client.exit.then(this.dispose); client.control!.onClipboardChange(content => { window.navigator.clipboard.writeText(content); }); client.deviceMessageStream!.pipeTo(new WritableStream({ write(message) { window.navigator.clipboard.writeText(message.content); } })).catch(() => { }); runInAction(() => { this.client = client; this.controlMessageWriter = client.controlMessageStream!.getWriter(); this.running = true; }); } catch (e: any) { Loading Loading @@ -846,7 +850,10 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.client.control!.pressBackOrTurnOnScreen(AndroidKeyEventAction.Down); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Down, }); }; handleBackPointerUp = (e: React.PointerEvent<HTMLDivElement>) => { Loading @@ -858,10 +865,13 @@ class ScrcpyPageState { return; } this.client.control!.pressBackOrTurnOnScreen(AndroidKeyEventAction.Up); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Up, }); }; handleHomePointerDown = async (e: React.PointerEvent<HTMLDivElement>) => { handleHomePointerDown = (e: React.PointerEvent<HTMLDivElement>) => { if (!this.client) { return; } Loading @@ -871,7 +881,8 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -879,7 +890,7 @@ class ScrcpyPageState { }); }; handleHomePointerUp = async (e: React.PointerEvent<HTMLDivElement>) => { handleHomePointerUp = (e: React.PointerEvent<HTMLDivElement>) => { if (!this.client) { return; } Loading @@ -888,7 +899,8 @@ class ScrcpyPageState { return; } await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -906,7 +918,8 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading @@ -923,7 +936,8 @@ class ScrcpyPageState { return; } await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading Loading @@ -967,7 +981,8 @@ class ScrcpyPageState { } const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.client.control!.injectTouch({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectTouch, action, pointerId: e.pointerType === "mouse" ? BigInt(-1) : BigInt(e.pointerId), screenWidth: this.client!.screenWidth!, Loading Loading @@ -1006,7 +1021,8 @@ class ScrcpyPageState { e.stopPropagation(); const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.client.control!.injectScroll({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectScroll, screenWidth: this.client!.screenWidth!, screenHeight: this.client!.screenHeight!, pointerX: x, Loading @@ -1028,7 +1044,10 @@ class ScrcpyPageState { const { key, code } = e; if (key.match(/^[!-`{-~]$/i)) { this.client.control!.injectText(key); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectText, text: key, }); return; } Loading @@ -1039,13 +1058,15 @@ class ScrcpyPageState { } as Record<string, AndroidKeyCode | undefined>)[code]; if (keyCode) { await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Down, keyCode, metaState: 0, repeat: 0, }); await this.client.control!.injectKeyCode({ this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, action: AndroidKeyEventAction.Up, keyCode, metaState: 0, Loading
libraries/adb/src/commands/sync/sync.ts +0 −1 Original line number Diff line number Diff line Loading @@ -177,7 +177,6 @@ export class AdbSync extends AutoDisposable { public override async dispose() { super.dispose(); await this.stream.close(); await this.writer.close(); } }
libraries/scrcpy/src/adb/client.ts +13 −8 Original line number Diff line number Diff line import { Adb, AdbSubprocessNoneProtocol, AdbSubprocessProtocol, AdbSync } from '@yume-chan/adb'; import { DecodeUtf8Stream, InspectStream, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { DecodeUtf8Stream, InspectStream, pipeFrom, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { ScrcpyControlClient } from '../control/index.js'; import { DEFAULT_SERVER_PATH, VideoStreamPacket } from '../options/index.js'; import { ScrcpyControlMessageSerializeStream, type ScrcpyControlMessage } from '../control/index.js'; import { ScrcpyDeviceMessageDeserializeStream, type ScrcpyDeviceMessage } from '../device-message/index.js'; import { DEFAULT_SERVER_PATH, type VideoStreamPacket } from '../options/index.js'; import type { AdbScrcpyOptions } from './options/index.js'; class ArrayToStream<T> extends ReadableStream<T>{ Loading Loading @@ -68,7 +69,7 @@ export class AdbScrcpyClient { ) { let sync!: AdbSync; return new WrapWritableStream<Uint8Array>({ start: async () => { async start() { sync = await adb.sync(); return sync.write(path); }, Loading Loading @@ -101,7 +102,7 @@ export class AdbScrcpyClient { ...options.formatServerArguments(), ], { // Scrcpy server doesn't split stdout and stderr, // Scrcpy server doesn't use stderr, // so disable Shell Protocol to simplify processing protocols: [AdbSubprocessNoneProtocol], } Loading Loading @@ -254,8 +255,11 @@ export class AdbScrcpyClient { private _videoStream: ReadableStream<VideoStreamPacket>; public get videoStream() { return this._videoStream; } private _control: ScrcpyControlClient | undefined; public get control() { return this._control; } private _controlMessageStream: WritableStream<ScrcpyControlMessage> | undefined; public get controlMessageStream() { return this._controlMessageStream; } private _deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined; public get deviceMessageStream() { return this._deviceMessageStream; } public constructor( options: AdbScrcpyOptions<any>, Loading @@ -277,7 +281,8 @@ export class AdbScrcpyClient { })); if (controlStream) { this._control = new ScrcpyControlClient(options, controlStream); this._controlMessageStream = pipeFrom(controlStream.writable, new ScrcpyControlMessageSerializeStream(options)); this._deviceMessageStream = controlStream.readable.pipeThrough(new ScrcpyDeviceMessageDeserializeStream()); } } Loading
libraries/scrcpy/src/adb/connection.ts +4 −8 Original line number Diff line number Diff line Loading @@ -36,8 +36,8 @@ export abstract class AdbScrcpyConnection implements Disposable { } export class AdbScrcpyForwardConnection extends AdbScrcpyConnection { private async connect(): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { return await this.adb.createSocket('localabstract:scrcpy'); private connect(): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { return this.adb.createSocket('localabstract:scrcpy'); } private async connectAndRetry(): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { Loading Loading @@ -94,12 +94,8 @@ export class AdbScrcpyReverseConnection extends AdbScrcpyConnection { private address!: string; public override async initialize(): Promise<void> { try { // try to unbind first await this.adb.reverse.remove('localabstract:scrcpy'); } catch { // ignore error } // try to unbind first, ignore errors await this.adb.reverse.remove('localabstract:scrcpy').catch(() => { }); const queue = new TransformStream<ReadableWritablePair<Uint8Array, Uint8Array>>(); this.streams = queue.readable.getReader(); Loading