diff --git a/libraries/adb/src/commands/subprocess/command.ts b/libraries/adb/src/commands/subprocess/command.ts index 27f8f80b4..5f3bda430 100644 --- a/libraries/adb/src/commands/subprocess/command.ts +++ b/libraries/adb/src/commands/subprocess/command.ts @@ -24,11 +24,13 @@ export interface AdbSubprocessOptions { * @default [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol] */ protocols: AdbSubprocessProtocolConstructor[]; + + signal?: AbortSignal; } -const DEFAULT_OPTIONS: AdbSubprocessOptions = { +const DEFAULT_OPTIONS = { protocols: [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol], -}; +} satisfies AdbSubprocessOptions; export interface AdbSubprocessWaitResult { stdout: string; @@ -42,7 +44,7 @@ export class AdbSubprocess extends AdbCommandBase { command?: string | string[], options?: Partial, ): Promise { - const { protocols } = { ...DEFAULT_OPTIONS, ...options }; + const { protocols, signal } = { ...DEFAULT_OPTIONS, ...options }; let Constructor: AdbSubprocessProtocolConstructor | undefined; for (const item of protocols) { @@ -63,7 +65,7 @@ export class AdbSubprocess extends AdbCommandBase { // spawn the default shell command = ""; } - return await Constructor[mode](this.adb, command); + return await Constructor[mode](this.adb, command, signal); } /** diff --git a/libraries/adb/src/commands/subprocess/protocols/none.ts b/libraries/adb/src/commands/subprocess/protocols/none.ts index bf6f9a680..9d6e43cb4 100644 --- a/libraries/adb/src/commands/subprocess/protocols/none.ts +++ b/libraries/adb/src/commands/subprocess/protocols/none.ts @@ -18,17 +18,19 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol { return true; } - static async pty(adb: Adb, command: string) { + static async pty(adb: Adb, command: string, signal?: AbortSignal) { return new AdbSubprocessNoneProtocol( await adb.createSocket(`shell:${command}`), + signal, ); } - static async raw(adb: Adb, command: string) { + static async raw(adb: Adb, command: string, signal?: AbortSignal) { // `shell,raw:${command}` also triggers raw mode, // But is not supported on Android version <7. return new AdbSubprocessNoneProtocol( await adb.createSocket(`exec:${command}`), + signal, ); } @@ -59,8 +61,11 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol { return this.#exit; } - constructor(socket: AdbSocket) { + constructor(socket: AdbSocket, signal?: AbortSignal) { + signal?.throwIfAborted(); + this.#socket = socket; + signal?.addEventListener("abort", () => void this.kill()); this.#stderr = new ReadableStream({ start: async (controller) => { diff --git a/libraries/adb/src/commands/subprocess/protocols/shell.ts b/libraries/adb/src/commands/subprocess/protocols/shell.ts index 38e9ebbb9..eb48699ba 100644 --- a/libraries/adb/src/commands/subprocess/protocols/shell.ts +++ b/libraries/adb/src/commands/subprocess/protocols/shell.ts @@ -55,16 +55,18 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol { return adb.canUseFeature(AdbFeature.ShellV2); } - static async pty(adb: Adb, command: string) { + static async pty(adb: Adb, command: string, signal?: AbortSignal) { // TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable return new AdbSubprocessShellProtocol( await adb.createSocket(`shell,v2,pty:${command}`), + signal, ); } - static async raw(adb: Adb, command: string) { + static async raw(adb: Adb, command: string, signal?: AbortSignal) { return new AdbSubprocessShellProtocol( await adb.createSocket(`shell,v2,raw:${command}`), + signal, ); } @@ -91,8 +93,11 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol { return this.#exit.promise; } - constructor(socket: AdbSocket) { + constructor(socket: AdbSocket, signal?: AbortSignal) { + signal?.throwIfAborted(); + this.#socket = socket; + signal?.addEventListener("abort", () => void this.kill()); let stdoutController!: PushReadableStreamController; let stderrController!: PushReadableStreamController; diff --git a/libraries/adb/src/commands/subprocess/protocols/types.ts b/libraries/adb/src/commands/subprocess/protocols/types.ts index 6c2e39c2a..22d0df4cc 100644 --- a/libraries/adb/src/commands/subprocess/protocols/types.ts +++ b/libraries/adb/src/commands/subprocess/protocols/types.ts @@ -53,10 +53,18 @@ export interface AdbSubprocessProtocolConstructor { isSupported(adb: Adb): MaybePromiseLike; /** Spawns an executable in PTY (interactive) mode. */ - pty(adb: Adb, command: string): MaybePromiseLike; + pty: ( + adb: Adb, + command: string, + signal?: AbortSignal, + ) => MaybePromiseLike; /** Spawns an executable and pipe the output. */ - raw(adb: Adb, command: string): MaybePromiseLike; + raw( + adb: Adb, + command: string, + signal?: AbortSignal, + ): MaybePromiseLike; /** Creates a new `AdbShell` by attaching to an exist `AdbSocket` */ new (socket: AdbSocket): AdbSubprocessProtocol; diff --git a/libraries/android-bin/src/logcat.ts b/libraries/android-bin/src/logcat.ts index 90eb45717..39f98f28b 100644 --- a/libraries/android-bin/src/logcat.ts +++ b/libraries/android-bin/src/logcat.ts @@ -80,13 +80,11 @@ export type LogcatFormat = (typeof LogcatFormat)[keyof typeof LogcatFormat]; export interface LogcatFormatModifiers { microseconds?: boolean; nanoseconds?: boolean; - printable?: boolean; year?: boolean; timezone?: boolean; epoch?: boolean; monotonic?: boolean; uid?: boolean; - descriptive?: boolean; } export interface LogcatOptions { diff --git a/libraries/scrcpy/src/android/key-event.ts b/libraries/scrcpy/src/android/key-event.ts index 9194000b8..863ff7d6a 100644 --- a/libraries/scrcpy/src/android/key-event.ts +++ b/libraries/scrcpy/src/android/key-event.ts @@ -30,8 +30,9 @@ export type AndroidKeyEventMeta = (typeof AndroidKeyEventMeta)[keyof typeof AndroidKeyEventMeta]; // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/KeyEvent.java;l=97;drc=95c1165bb895dd844e1793460710f7163dd330a3 -// Most names follow Web API `KeyboardEvent.code`, -// Android-only (not exist in HID keyboard standard) keys are prefixed by `Android`. +// Android key code to Chrome key code: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/keyboard_code_conversion_android.cc +// Chrome key code to DOM key code: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/dom/dom_code_data.inc +// Some keys are not mapped to `KeyboardEvent.code`, only to `KeyboardEvent.key`: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/dom/dom_key_data.inc export const AndroidKeyCode = { AndroidHome: 3, AndroidBack: 4,