// ==UserScript== // @license MIT // @name Bing 搜索栏中使用中文输入法导致删字修复 // @description 修复在 Bing 搜索栏中使用输入法时,光标前已有文字被删除的问题 // @name:en Bing Search Box IME Fix // @description:en Fixes the issue where existing text before the cursor is deleted when using IME in the Bing search box // @version 2.0.0 // @author chuochuo22 // @match https://www.bing.com/* // @match https://cn.bing.com/* // @grant none // @run-at document-start // @namespace https://greasyfork.org/users/1581974 // ==/UserScript== (function () { 'use strict'; // 获取底层 value 的 getter/setter(绕过任何第三方拦截) const proto = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); function patchInput(input) { if (input.__imePatchApplied) return; input.__imePatchApplied = true; let savedValue = null; let savedCaret = null; let pendingIMERestore = false; // keydown 时保存当前内容和光标位置 // 退格键 / Delete 键不保存(防止误恢复真正的删除操作) input.addEventListener('keydown', (e) => { if (e.key !== 'Backspace' && e.key !== 'Delete') { const start = input.selectionStart; const end = input.selectionEnd; if (start !== end) { // 有选中:预计算删除选中后的值和光标位置 const current = proto.get.call(input); savedValue = current.slice(0, start) + current.slice(end); savedCaret = start; } else { // 无选中:正常保存 savedValue = proto.get.call(input); savedCaret = start; } pendingIMERestore = false; } else { savedValue = null; } }, true); // input 事件:检测到 IME 前置的 deleteContentBackward,标记待恢复 input.addEventListener('input', (e) => { if (e.inputType === 'deleteContentBackward' && savedValue !== null) { pendingIMERestore = true; } }, true); // compositionstart:IME 正式开始,此时恢复被删掉的内容 // 使用底层 proto.set 绕过 Bing 自身的 value 拦截 input.addEventListener('compositionstart', () => { if (pendingIMERestore && savedValue !== null) { proto.set.call(input, savedValue); input.setSelectionRange(savedCaret, savedCaret); } pendingIMERestore = false; savedValue = null; }, true); } // 扫描页面上所有 Bing 搜索框并注入补丁 function patchAllInputs() { document.querySelectorAll( '#sb_form_q, #sq_form_q, input[name="q"]' ).forEach(patchInput); } // MutationObserver:应对 Bing 重建 DOM 后输入框被替换的情况 function startObserver() { const observer = new MutationObserver((mutations) => { for (const m of mutations) { if (m.addedNodes.length > 0) { patchAllInputs(); break; } } }); observer.observe(document.body, { childList: true, subtree: true }); } // 入口:等 DOM 就绪后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { patchAllInputs(); startObserver(); }); } else { patchAllInputs(); startObserver(); } })();