求助,写了一个用手机浏览器控制电脑远程输入的工具,但是 ios 端的语音输入有个问题解决不了

我写了一个脚本,绑定一个 http 服务,用另一个设备的浏览器打开后,在里面输入文本,可以捕获输入文本、按键,同步到 server 端。主要用途是:在电脑上运行这个服务,在手机浏览器上打开这个页面,就可以在手机端进行语音输入,将键入事件同步到电脑端。

相关代码在:github: web_remote_input

使用图片:

下面的问题需要懂前端的朋友解答。

这个实时输入的实现,就是在 textarea 下注册了一系列的事件监听:

        messageInput.addEventListener("compositionstart", start_chinese);
        messageInput.addEventListener("compositionend", finish_chinese);
        messageInput.addEventListener("input", send_input);
        messageInput.addEventListener("paste", send_paste);
        messageInput.addEventListener("keydown", send_key);
        messageInput.addEventListener("click", clear_text);

然后把这些事件通过 socketio 发给 server 端:

// 开始输入中文
function start_chinese(event) {
    messageInput.isComposing = true;
}

// 结束输入中文
function finish_chinese(event) {
    // 清除正在输入中文的标记
    messageInput.isComposing = false;

    // 发送中文内容
    socket.emit("word", event.data);
}

// 发送输入的字符
function send_input(event) {
    if (event.inputType === "insertText") {
        // 发送插入的字符
        var message = event.data;
        socket.emit("input", message);
    }
}

在安卓上时,在输入框里使用语音输入,这个输入框会收到 insertFromComposition 类型的 input 事件。

但在 iOS 设备上,用原生输入法的语音输入功能,出了意外,会收到一系列的 insertText 事件,但没有收到任何 deleteContentBackward 事件。然而,输入框中的文本的表现是之前输入的文本被更新了。

当我用语音输入说 「快速地飞过。」 时,这是事件记录:

before_input_event: {'inputType': 'insertText', 'data': '快', 'targetValue': ''}
input_event: {'inputType': 'insertText', 'data': '快', 'targetValue': '快'}

before_input_event: {'inputType': 'insertText', 'data': '快速', 'targetValue': '快'}
input_event: {'inputType': 'insertText', 'data': '快速', 'targetValue': '快速'}

before_input_event: {'inputType': 'insertText', 'data': '快速。', 'targetValue': '快速'}
input_event: {'inputType': 'insertText', 'data': '快速。', 'targetValue': '快速。'}

before_input_event: {'inputType': 'insertText', 'data': '快速的。', 'targetValue': '快速。'}
input_event: {'inputType': 'insertText', 'data': '快速的。', 'targetValue': '快速的。'}

before_input_event: {'inputType': 'insertText', 'data': '快速地飞过。', 'targetValue': '快速的。'}
input_event: {'inputType': 'insertText', 'data': '快速地飞过。', 'targetValue': '快速地飞过。'}

before_input_event: {'inputType': 'insertText', 'data': '快速地飞过。', 'targetValue': '快速地飞过。'}
input_event: {'inputType': 'insertText', 'data': '快速地飞过。', 'targetValue': '快速地飞过。'}

这些输出,明显就是语音输入的时候,分段识别的回调结果,同步到前端了,覆盖了之前的识别结果,于是在手机端最后显示的结果就是「快速地飞过。」,但当这一连串捕获的 input event 传到电脑端后,就会是「快快速快速。快速的。快速地飞过。快速地飞过。」

我的猜想是,可能有我没有捕获到的其他事件,允许语音输入直接覆盖之前输入的文本。有没有办法捕获原始更新操作,或者了解为什么输入事件与输入框中的实际文本不一致?

@feeshy 你以前有这样一个贴子 Windows PC数字输入新思路 ,用移动设备给电脑输入。这个就可以了,任何设备用浏览器访问,就可以给电脑远程输入了。

我之前做这个功能的时候,直接放弃了即时输入功能,放了个按钮,输入完了一次性提交。因为输入法在输入过程中会出现多次输入和修改的现象,尤其是语音输入,要猜好多次。即时发送功能对我来说不是必要的。

我这个实时模式用在安卓端可以正常用语音输入,在 ios 端可以正常用百度输入法的语音输入。目前就是ios原生输入法的语音输入有问题。

是,输入法千奇百怪,而且浏览器也是。

好东西 mark一下
我之前用的是一个叫做Etherpad的软件实现类似功能
有你这个就方便多了
能不能做成exe呢?

明显可以看出来
before_input_event: {‘inputType’: ‘insertText’, ‘data’: ‘快’, ‘targetValue’: ‘’}
这个就是用 快 替换掉末尾的空白 也就是插入 快 字

before_input_event: {‘inputType’: ‘insertText’, ‘data’: ‘快速’, ‘targetValue’: ‘快’}

这个就是用 快速 替换掉末尾的 快 字

之后依次滚动替换 最后变成 快速地飞过

所以压根不需要什么删除指令

不懂 我瞎猜的
你直接在电脑端按照滚动替换 而不是插入去处理字符串应该就好了吧

这个确实可以做,我也做出来了,但是为了兼容其他输入法的输入行为需要加一大堆逻辑判断,很不优雅,暂时先注释掉了。最好是能够直接获得他是从哪里更新的原始事件。