Loading apps/demo/src/pages/scrcpy.tsx +18 −33 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, ScrcpyControlMessage, ScrcpyControlMessageType, 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, ScrcpyDeviceMessageType, 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,7 +243,6 @@ 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 @@ -364,7 +363,7 @@ class ScrcpyPageState { iconProps: { iconName: Icons.Orientation }, iconOnly: true, text: 'Rotate Device', onClick: () => { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.RotateDevice }); }, onClick: () => { this.client!.controlMessageSerializer!.rotateDevice(); }, }); result.push({ Loading Loading @@ -795,13 +794,16 @@ class ScrcpyPageState { client.deviceMessageStream!.pipeTo(new WritableStream({ write(message) { switch (message.type) { case ScrcpyDeviceMessageType.Clipboard: window.navigator.clipboard.writeText(message.content); break; } } })).catch(() => { }); runInAction(() => { this.client = client; this.controlMessageWriter = client.controlMessageStream!.getWriter(); this.running = true; }); } catch (e: any) { Loading Loading @@ -850,10 +852,7 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Down, }); this.client!.controlMessageSerializer!.backOrScreenOn(AndroidKeyEventAction.Down); }; handleBackPointerUp = (e: React.PointerEvent<HTMLDivElement>) => { Loading @@ -865,10 +864,7 @@ class ScrcpyPageState { return; } this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Up, }); this.client!.controlMessageSerializer!.backOrScreenOn(AndroidKeyEventAction.Up); }; handleHomePointerDown = (e: React.PointerEvent<HTMLDivElement>) => { Loading @@ -881,8 +877,7 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -899,8 +894,7 @@ class ScrcpyPageState { return; } this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -918,8 +912,7 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading @@ -936,8 +929,7 @@ class ScrcpyPageState { return; } this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading Loading @@ -981,8 +973,7 @@ class ScrcpyPageState { } const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectTouch, this.client!.controlMessageSerializer!.injectTouch({ action, pointerId: e.pointerType === "mouse" ? BigInt(-1) : BigInt(e.pointerId), screenWidth: this.client!.screenWidth!, Loading Loading @@ -1021,8 +1012,7 @@ class ScrcpyPageState { e.stopPropagation(); const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectScroll, this.client!.controlMessageSerializer!.injectScroll({ screenWidth: this.client!.screenWidth!, screenHeight: this.client!.screenHeight!, pointerX: x, Loading @@ -1044,10 +1034,7 @@ class ScrcpyPageState { const { key, code } = e; if (key.match(/^[!-`{-~]$/i)) { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectText, text: key, }); this.client!.controlMessageSerializer!.injectText(key); return; } Loading @@ -1058,15 +1045,13 @@ class ScrcpyPageState { } as Record<string, AndroidKeyCode | undefined>)[code]; if (keyCode) { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Down, keyCode, metaState: 0, repeat: 0, }); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Up, keyCode, metaState: 0, Loading libraries/scrcpy/src/adb/client.ts +5 −5 Original line number Diff line number Diff line import { Adb, AdbSubprocessNoneProtocol, AdbSubprocessProtocol, AdbSync } from '@yume-chan/adb'; import { DecodeUtf8Stream, InspectStream, pipeFrom, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { DecodeUtf8Stream, InspectStream, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { ScrcpyControlMessageSerializeStream, type ScrcpyControlMessage } from '../control/index.js'; import { ScrcpyControlMessageSerializer } 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'; Loading Loading @@ -255,8 +255,8 @@ export class AdbScrcpyClient { private _videoStream: ReadableStream<VideoStreamPacket>; public get videoStream() { return this._videoStream; } private _controlMessageStream: WritableStream<ScrcpyControlMessage> | undefined; public get controlMessageStream() { return this._controlMessageStream; } private _controlMessageSerializer: ScrcpyControlMessageSerializer | undefined; public get controlMessageSerializer() { return this._controlMessageSerializer; } private _deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined; public get deviceMessageStream() { return this._deviceMessageStream; } Loading @@ -281,7 +281,7 @@ export class AdbScrcpyClient { })); if (controlStream) { this._controlMessageStream = pipeFrom(controlStream.writable, new ScrcpyControlMessageSerializeStream(options)); this._controlMessageSerializer = new ScrcpyControlMessageSerializer(controlStream.writable, options); this._deviceMessageStream = controlStream.readable.pipeThrough(new ScrcpyDeviceMessageDeserializeStream()); } } Loading libraries/scrcpy/src/control/index.ts +1 −1 Original line number Diff line number Diff line Loading @@ -2,5 +2,5 @@ export * from './inject-keycode.js'; export * from './inject-text.js'; export * from './inject-touch.js'; export * from './rotate-device.js'; export * from './stream.js'; export * from './serializer.js'; export * from './type.js'; libraries/scrcpy/src/control/serializer.ts 0 → 100644 +78 −0 Original line number Diff line number Diff line import type { WritableStreamDefaultWriter } from '@yume-chan/stream-extra'; import type { ScrcpyInjectScrollControlMessage1_22, ScrcpyOptions } from '../options/index.js'; import { AndroidKeyEventAction, ScrcpyInjectKeyCodeControlMessage } from './inject-keycode.js'; import { ScrcpyInjectTextControlMessage } from './inject-text.js'; import { ScrcpyInjectTouchControlMessage } from './inject-touch.js'; import { ScrcpyRotateDeviceControlMessage } from './rotate-device.js'; import { ScrcpyControlMessageType } from './type.js'; export class ScrcpyControlMessageSerializer { private options: ScrcpyOptions<any>; /** Control message type values for current version of server */ private types: ScrcpyControlMessageType[]; private writer: WritableStreamDefaultWriter<Uint8Array>; public constructor(stream: WritableStream<Uint8Array>, options: ScrcpyOptions<any>) { this.options = options; this.types = options.getControlMessageTypes(); this.writer = stream.getWriter(); } public getTypeValue(type: ScrcpyControlMessageType): number { const value = this.types.indexOf(type); if (value === -1) { throw new Error('Not supported'); } return value; } public injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, 'type'>) { return this.writer.write(ScrcpyInjectKeyCodeControlMessage.serialize({ ...message, type: this.getTypeValue(ScrcpyControlMessageType.InjectKeyCode), })); } public injectText(text: string) { return this.writer.write(ScrcpyInjectTextControlMessage.serialize({ text, type: this.getTypeValue(ScrcpyControlMessageType.InjectText), })); } public injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, 'type'>) { return this.writer.write(ScrcpyInjectTouchControlMessage.serialize({ ...message, type: this.getTypeValue(ScrcpyControlMessageType.InjectTouch), })); } public injectScroll(message: Omit<ScrcpyInjectScrollControlMessage1_22, 'type'>) { return this.writer.write(this.options.serializeInjectScrollControlMessage({ ...message, type: this.getTypeValue(ScrcpyControlMessageType.InjectScroll), })); } public async backOrScreenOn(action: AndroidKeyEventAction) { const buffer = this.options.serializeBackOrScreenOnControlMessage({ action, type: this.getTypeValue(ScrcpyControlMessageType.BackOrScreenOn), }); if (buffer) { return await this.writer.write(buffer); } } public rotateDevice() { return this.writer.write(ScrcpyRotateDeviceControlMessage.serialize({ type: this.getTypeValue(ScrcpyControlMessageType.RotateDevice), })); } public close() { return this.writer.close(); } }; libraries/scrcpy/src/control/stream.tsdeleted 100644 → 0 +0 −79 Original line number Diff line number Diff line import { TransformStream } from '@yume-chan/stream-extra'; import type { ScrcpyBackOrScreenOnControlMessage1_18, ScrcpyInjectScrollControlMessage1_22, ScrcpyOptions } from '../options/index.js'; import { ScrcpyInjectKeyCodeControlMessage } from './inject-keycode.js'; import { ScrcpyInjectTextControlMessage } from './inject-text.js'; import { ScrcpyInjectTouchControlMessage } from './inject-touch.js'; import { ScrcpyRotateDeviceControlMessage } from './rotate-device.js'; import { ScrcpyControlMessageType } from './type.js'; export type ScrcpyControlMessage = | ScrcpyInjectKeyCodeControlMessage | ScrcpyInjectTextControlMessage | ScrcpyInjectTouchControlMessage | ScrcpyInjectScrollControlMessage1_22 | ScrcpyBackOrScreenOnControlMessage1_18 | ScrcpyRotateDeviceControlMessage; export class ScrcpyControlMessageSerializeStream extends TransformStream<ScrcpyControlMessage, Uint8Array> { public constructor(options: ScrcpyOptions<any>) { // Get control message types for current version of server const types = options.getControlMessageTypes(); super({ transform(message, controller) { const type = types.indexOf(message.type); if (type === -1) { throw new Error('Not supported'); } switch (message.type) { case ScrcpyControlMessageType.InjectKeyCode: controller.enqueue(ScrcpyInjectKeyCodeControlMessage.serialize({ ...message, type })); break; case ScrcpyControlMessageType.InjectText: controller.enqueue(ScrcpyInjectTextControlMessage.serialize({ ...message, type, })); break; case ScrcpyControlMessageType.InjectTouch: // ADB streams are actually pretty low-bandwidth and laggy // Re-sample move events to avoid flooding the connection controller.enqueue(ScrcpyInjectTouchControlMessage.serialize({ ...message, type, })); break; case ScrcpyControlMessageType.InjectScroll: controller.enqueue(options.serializeInjectScrollControlMessage({ ...message, type, })) break; case ScrcpyControlMessageType.BackOrScreenOn: { const buffer = options.serializeBackOrScreenOnControlMessage({ ...message, type, }); if (buffer) { controller.enqueue(buffer); } } break; case ScrcpyControlMessageType.RotateDevice: controller.enqueue(ScrcpyRotateDeviceControlMessage.serialize({ type, })); break; } } }) } } Loading
apps/demo/src/pages/scrcpy.tsx +18 −33 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, ScrcpyControlMessage, ScrcpyControlMessageType, 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, ScrcpyDeviceMessageType, 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,7 +243,6 @@ 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 @@ -364,7 +363,7 @@ class ScrcpyPageState { iconProps: { iconName: Icons.Orientation }, iconOnly: true, text: 'Rotate Device', onClick: () => { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.RotateDevice }); }, onClick: () => { this.client!.controlMessageSerializer!.rotateDevice(); }, }); result.push({ Loading Loading @@ -795,13 +794,16 @@ class ScrcpyPageState { client.deviceMessageStream!.pipeTo(new WritableStream({ write(message) { switch (message.type) { case ScrcpyDeviceMessageType.Clipboard: window.navigator.clipboard.writeText(message.content); break; } } })).catch(() => { }); runInAction(() => { this.client = client; this.controlMessageWriter = client.controlMessageStream!.getWriter(); this.running = true; }); } catch (e: any) { Loading Loading @@ -850,10 +852,7 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Down, }); this.client!.controlMessageSerializer!.backOrScreenOn(AndroidKeyEventAction.Down); }; handleBackPointerUp = (e: React.PointerEvent<HTMLDivElement>) => { Loading @@ -865,10 +864,7 @@ class ScrcpyPageState { return; } this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.BackOrScreenOn, action: AndroidKeyEventAction.Up, }); this.client!.controlMessageSerializer!.backOrScreenOn(AndroidKeyEventAction.Up); }; handleHomePointerDown = (e: React.PointerEvent<HTMLDivElement>) => { Loading @@ -881,8 +877,7 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -899,8 +894,7 @@ class ScrcpyPageState { return; } this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.Home, repeat: 0, Loading @@ -918,8 +912,7 @@ class ScrcpyPageState { } e.currentTarget.setPointerCapture(e.pointerId); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Down, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading @@ -936,8 +929,7 @@ class ScrcpyPageState { return; } this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Up, keyCode: AndroidKeyCode.AppSwitch, repeat: 0, Loading Loading @@ -981,8 +973,7 @@ class ScrcpyPageState { } const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectTouch, this.client!.controlMessageSerializer!.injectTouch({ action, pointerId: e.pointerType === "mouse" ? BigInt(-1) : BigInt(e.pointerId), screenWidth: this.client!.screenWidth!, Loading Loading @@ -1021,8 +1012,7 @@ class ScrcpyPageState { e.stopPropagation(); const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectScroll, this.client!.controlMessageSerializer!.injectScroll({ screenWidth: this.client!.screenWidth!, screenHeight: this.client!.screenHeight!, pointerX: x, Loading @@ -1044,10 +1034,7 @@ class ScrcpyPageState { const { key, code } = e; if (key.match(/^[!-`{-~]$/i)) { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectText, text: key, }); this.client!.controlMessageSerializer!.injectText(key); return; } Loading @@ -1058,15 +1045,13 @@ class ScrcpyPageState { } as Record<string, AndroidKeyCode | undefined>)[code]; if (keyCode) { this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Down, keyCode, metaState: 0, repeat: 0, }); this.controlMessageWriter!.write({ type: ScrcpyControlMessageType.InjectKeyCode, this.client!.controlMessageSerializer!.injectKeyCode({ action: AndroidKeyEventAction.Up, keyCode, metaState: 0, Loading
libraries/scrcpy/src/adb/client.ts +5 −5 Original line number Diff line number Diff line import { Adb, AdbSubprocessNoneProtocol, AdbSubprocessProtocol, AdbSync } from '@yume-chan/adb'; import { DecodeUtf8Stream, InspectStream, pipeFrom, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { DecodeUtf8Stream, InspectStream, ReadableStream, SplitStringStream, WrapWritableStream, WritableStream, type ReadableWritablePair } from '@yume-chan/stream-extra'; import { ScrcpyControlMessageSerializeStream, type ScrcpyControlMessage } from '../control/index.js'; import { ScrcpyControlMessageSerializer } 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'; Loading Loading @@ -255,8 +255,8 @@ export class AdbScrcpyClient { private _videoStream: ReadableStream<VideoStreamPacket>; public get videoStream() { return this._videoStream; } private _controlMessageStream: WritableStream<ScrcpyControlMessage> | undefined; public get controlMessageStream() { return this._controlMessageStream; } private _controlMessageSerializer: ScrcpyControlMessageSerializer | undefined; public get controlMessageSerializer() { return this._controlMessageSerializer; } private _deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined; public get deviceMessageStream() { return this._deviceMessageStream; } Loading @@ -281,7 +281,7 @@ export class AdbScrcpyClient { })); if (controlStream) { this._controlMessageStream = pipeFrom(controlStream.writable, new ScrcpyControlMessageSerializeStream(options)); this._controlMessageSerializer = new ScrcpyControlMessageSerializer(controlStream.writable, options); this._deviceMessageStream = controlStream.readable.pipeThrough(new ScrcpyDeviceMessageDeserializeStream()); } } Loading
libraries/scrcpy/src/control/index.ts +1 −1 Original line number Diff line number Diff line Loading @@ -2,5 +2,5 @@ export * from './inject-keycode.js'; export * from './inject-text.js'; export * from './inject-touch.js'; export * from './rotate-device.js'; export * from './stream.js'; export * from './serializer.js'; export * from './type.js';
libraries/scrcpy/src/control/serializer.ts 0 → 100644 +78 −0 Original line number Diff line number Diff line import type { WritableStreamDefaultWriter } from '@yume-chan/stream-extra'; import type { ScrcpyInjectScrollControlMessage1_22, ScrcpyOptions } from '../options/index.js'; import { AndroidKeyEventAction, ScrcpyInjectKeyCodeControlMessage } from './inject-keycode.js'; import { ScrcpyInjectTextControlMessage } from './inject-text.js'; import { ScrcpyInjectTouchControlMessage } from './inject-touch.js'; import { ScrcpyRotateDeviceControlMessage } from './rotate-device.js'; import { ScrcpyControlMessageType } from './type.js'; export class ScrcpyControlMessageSerializer { private options: ScrcpyOptions<any>; /** Control message type values for current version of server */ private types: ScrcpyControlMessageType[]; private writer: WritableStreamDefaultWriter<Uint8Array>; public constructor(stream: WritableStream<Uint8Array>, options: ScrcpyOptions<any>) { this.options = options; this.types = options.getControlMessageTypes(); this.writer = stream.getWriter(); } public getTypeValue(type: ScrcpyControlMessageType): number { const value = this.types.indexOf(type); if (value === -1) { throw new Error('Not supported'); } return value; } public injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, 'type'>) { return this.writer.write(ScrcpyInjectKeyCodeControlMessage.serialize({ ...message, type: this.getTypeValue(ScrcpyControlMessageType.InjectKeyCode), })); } public injectText(text: string) { return this.writer.write(ScrcpyInjectTextControlMessage.serialize({ text, type: this.getTypeValue(ScrcpyControlMessageType.InjectText), })); } public injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, 'type'>) { return this.writer.write(ScrcpyInjectTouchControlMessage.serialize({ ...message, type: this.getTypeValue(ScrcpyControlMessageType.InjectTouch), })); } public injectScroll(message: Omit<ScrcpyInjectScrollControlMessage1_22, 'type'>) { return this.writer.write(this.options.serializeInjectScrollControlMessage({ ...message, type: this.getTypeValue(ScrcpyControlMessageType.InjectScroll), })); } public async backOrScreenOn(action: AndroidKeyEventAction) { const buffer = this.options.serializeBackOrScreenOnControlMessage({ action, type: this.getTypeValue(ScrcpyControlMessageType.BackOrScreenOn), }); if (buffer) { return await this.writer.write(buffer); } } public rotateDevice() { return this.writer.write(ScrcpyRotateDeviceControlMessage.serialize({ type: this.getTypeValue(ScrcpyControlMessageType.RotateDevice), })); } public close() { return this.writer.close(); } };
libraries/scrcpy/src/control/stream.tsdeleted 100644 → 0 +0 −79 Original line number Diff line number Diff line import { TransformStream } from '@yume-chan/stream-extra'; import type { ScrcpyBackOrScreenOnControlMessage1_18, ScrcpyInjectScrollControlMessage1_22, ScrcpyOptions } from '../options/index.js'; import { ScrcpyInjectKeyCodeControlMessage } from './inject-keycode.js'; import { ScrcpyInjectTextControlMessage } from './inject-text.js'; import { ScrcpyInjectTouchControlMessage } from './inject-touch.js'; import { ScrcpyRotateDeviceControlMessage } from './rotate-device.js'; import { ScrcpyControlMessageType } from './type.js'; export type ScrcpyControlMessage = | ScrcpyInjectKeyCodeControlMessage | ScrcpyInjectTextControlMessage | ScrcpyInjectTouchControlMessage | ScrcpyInjectScrollControlMessage1_22 | ScrcpyBackOrScreenOnControlMessage1_18 | ScrcpyRotateDeviceControlMessage; export class ScrcpyControlMessageSerializeStream extends TransformStream<ScrcpyControlMessage, Uint8Array> { public constructor(options: ScrcpyOptions<any>) { // Get control message types for current version of server const types = options.getControlMessageTypes(); super({ transform(message, controller) { const type = types.indexOf(message.type); if (type === -1) { throw new Error('Not supported'); } switch (message.type) { case ScrcpyControlMessageType.InjectKeyCode: controller.enqueue(ScrcpyInjectKeyCodeControlMessage.serialize({ ...message, type })); break; case ScrcpyControlMessageType.InjectText: controller.enqueue(ScrcpyInjectTextControlMessage.serialize({ ...message, type, })); break; case ScrcpyControlMessageType.InjectTouch: // ADB streams are actually pretty low-bandwidth and laggy // Re-sample move events to avoid flooding the connection controller.enqueue(ScrcpyInjectTouchControlMessage.serialize({ ...message, type, })); break; case ScrcpyControlMessageType.InjectScroll: controller.enqueue(options.serializeInjectScrollControlMessage({ ...message, type, })) break; case ScrcpyControlMessageType.BackOrScreenOn: { const buffer = options.serializeBackOrScreenOnControlMessage({ ...message, type, }); if (buffer) { controller.enqueue(buffer); } } break; case ScrcpyControlMessageType.RotateDevice: controller.enqueue(ScrcpyRotateDeviceControlMessage.serialize({ type, })); break; } } }) } }