回答
感觉实现起来很困难,但是我觉得下面的两种方案应该可以模拟一下类似的功能:
- 如果是简单的脚本,比如从一个文本框中监听你输入的内容。那么我觉得可以在每次循环前等待当前屏幕上出现对应的控件再进行。这个方式适用于比较简单的逻辑,和界面的耦合没有那么强。例如这样
const AIM_PACKAGE_NAME: string = "com.tencent.aim";
while (packageName(AIM_PACKAGE_NAME).exists()) {
// Do something
sleep(1000);
}
- 你可以自己创建一个操作队列,其中的每一个操作都是一个对象,包括了执行这一步的必要条件(主要是需要什么控件,以此来保证不会出现开始运行而找不到控件出现的异常问题)、要执行的步骤和当前队列的状态。然后就是需要尽可能的细化操作,将每一次的 API 调用尽可能的分离开,保证能够随时停下。如果用伪代码表示就类似于这样:
enum OperationStatus {
Pending = 0,
Fullfilled = 1,
rejected = 2,
}
type OperationExecutor<TArgument, TReturn> = (
argument: TArgument,
resolve: (value: TReturn) => void,
reject: (reason?: any) => void
) => void;
class Operation<TArgument, TReturn> {
private _operation_state: OperationStatus;
private _executor: OperationExecutor<TArgument, TReturn>;
private _resolve_value?: TReturn;
private _reject_reason?: unknown;
public constructor(executer: OperationExecutor<TArgument, TReturn>) {
this._operation_state = OperationStatus.Pending;
this._executor = executer;
}
public get state(): OperationStatus {
return this._operation_state;
}
public execute(arg: TArgument): TReturn | unknown {
try {
this._executor(arg, this._resolve, this._reject);
this._operation_state = OperationStatus.Fullfilled;
return this._resolve_value;
} catch (error) {
this._reject_reason = error;
this._operation_state = OperationStatus.rejected;
return this._reject_reason;
}
}
private _resolve(value: TReturn): void {
this._resolve_value = value;
}
private _reject(reason?: any): void {
this._reject_reason = reason;
}
}
代码娃娃胡写的求轻喷,具体可以借鉴 JS 里的 Promise 。然后另外其一个新的线程来处理中断信号。
let system_state = threads.atomic(0);
let key_down_number = 0;
let operations: Operation<number, number>[] = [
new Operation(() => 10),
new Operation((value: number) => value + 2),
]
events.observeKey();
events.onKeyDown("volume_down", () => {
if (key_down_number === 3) {
system_state.set(~system_state.get());
key_down_number = 0;
} else {
key_down_number += 1;
}
});
let result: any = undefined;
for (let operation of operations) {
if (system_state.get() === -1) {
continue
}
if (operation.state !== OperationStatus.Pending) {
continue
}
result = operation.execute(result);
}
上面的代码都没有经过测试,只是示意不保证能够直接运行~
0