我主力用微信输入法,但使用过程中经常莫名其妙切回 ABC。为了把 ABC 从输入源列表里移除,我和 AI 来回排查了一轮,最后确认:重启之后,ABC 没有再出现。

这次最值得记录的,是中途差点把一个猜测当成了原因:看到重启后 ABC 还在,就认定 macOS 把它加回来了,却没有先确认修改是否真正写进了目标文件。

1. 想移除的是输入源

我要做的是从当前用户的输入源列表里去掉 ABC,保留微信输入法。这里涉及的是用户偏好设置,没有必要删除系统输入法文件或关闭 SIP。

正常管理输入源的入口是「系统设置 → 键盘 → 文字输入 → 编辑」。如果只是排查自动切换,也可以先检查「自动切换到文稿的输入法」以及大写锁定键切换输入源的设置。这些选项的作用见 Apple 的输入源设置说明

这次后续的排查集中在用户配置文件:

~/Library/Preferences/com.apple.HIToolbox.plist

它里面有启用的输入源、输入源历史记录和当前选择等信息。

2. 第一次修改后,ABC 还在

最初我按建议手动编辑 plist,还把修改后的 XML 贴给 AI 检查。那份文本有两个值得注意的问题:

  • AppleEnabledInputSources 后面缺少开头的 <array>,却保留了结尾的 </array>。如果文件与粘贴文本一致,XML 结构就是无效的;也可能只是复制时漏了一行。
  • AppleInputSourceHistoryAppleCurrentKeyboardLayoutInputSourceID 里还有 ABC 的引用。

所以「在编辑器里删掉了一项」并不等于已经获得一份有效、完整且写回成功的配置。

后来我反馈「重启之后 ABC 还在」,AI 随即判断:macOS 在重启时自动恢复了 ABC,需要删除后锁定 plist。

这个判断下早了。 当时没有重启前读取真实文件的结果,也没有前后内容对比。仅凭「重启后还在」,无法区分以下两种情况:

修改没有成功写回目标文件 → 重启后仍然是原配置
修改已写回目标文件 → 后续又被其他进程改回

我当时确认的是手动编辑后重启没有达到目的,并没有验证过「在系统设置里删除成功,重启又恢复」这条过程。

3. 转机:VS Code 打开后的文件名变了

接着我发现,用 VS Code 打开 com.apple.HIToolbox.plist 后,编辑器里显示的却是类似这样的名字:

com.apple.HIToolbox.f65f7d.plist

更关键的是:文件列表里只有原来的那一个文件,但每次双击打开都会看到带后缀的名字;保存、关闭、再打开,之前的修改又没有了。

这让我们开始怀疑,编辑器展示的是转换后的临时副本,或者保存过程没有把修改写回真正的 plist。于是排查重点从「重启时发生了什么」转到了「到底改了哪个文件」。

不过,当时没有继续核查具体扩展、临时文件路径或保存日志,因此不能断言一定是哪一个扩展出了问题,也不能证明原文件每次都一个字节没变。文件名异常是线索,不能单凭它还原整条保存链路。

同样,记录里没有 file 命令的实际输出,不能把「原文件已确认是二进制 plist」当成现场证据。plist 可以是 XML 或二进制格式,实际格式需要检查。

下一步就很明确了:绕开这条编辑器路径,直接读写真实文件,并在重启前检查结果。

4. 最后一轮方案:直接修改、校验,再重启

下面整理最后一轮方案的核心步骤,并补上备份和失败检查。它是这次问题的处理记录,不是 Apple 提供的通用移除接口;不同版本的配置结构可能有差异。先确认微信输入法可用,再关闭系统设置和正在编辑该 plist 的窗口。

4.1 确认路径,先备份

在同一个终端会话中执行:

INPUT_PLIST="$HOME/Library/Preferences/com.apple.HIToolbox.plist"
INPUT_BACKUP="$HOME/Desktop/HIToolbox-$(date +%Y%m%d-%H%M%S).plist.backup"

file "$INPUT_PLIST"
ls -lO "$INPUT_PLIST"
cp "$INPUT_PLIST" "$INPUT_BACKUP"

file 用来看实际格式,ls -lO 用来看文件标志。确认备份成功后再继续。如果之前已经锁过文件,标志中有 uchg,先解锁:

chflags nouchg "$INPUT_PLIST"

4.2 用 Python 直接处理 plist

最后一轮建议还包括在修改前重启当前用户可操作的 cfprefsd

killall cfprefsd 2>/dev/null

cfprefsdCFPreferencesNSUserDefaults 提供偏好设置服务,可用 man cfprefsd 查看说明。缓存或后续写回是需要考虑的因素,但这次没有单独验证它是否造成了回写。上面的命令也不等于获得了一段「系统绝对不会再写配置」的时间窗口。

接下来需要可用的 python3。Python 的 plistlib 能直接读取 XML 和二进制 plist,不需要先在编辑器里转换格式。

python3 - <<'PY'
import plistlib
from pathlib import Path

p = Path.home() / "Library/Preferences/com.apple.HIToolbox.plist"
data = plistlib.loads(p.read_bytes())
if not isinstance(data, dict):
    raise SystemExit("配置不是预期的字典结构,停止修改。")

def is_abc(item):
    return isinstance(item, dict) and (
        item.get("KeyboardLayout Name") == "ABC"
        or item.get("InputSource ID") == "com.apple.keylayout.ABC"
    )

for key in (
    "AppleEnabledInputSources",
    "AppleInputSourceHistory",
    "AppleSelectedInputSources",
):
    if key not in data:
        continue
    if not isinstance(data[key], list):
        raise SystemExit(f"{key} 不是预期的数组,停止修改。")
    data[key] = [item for item in data[key] if not is_abc(item)]

for key in (
    "AppleCurrentKeyboardLayoutInputSourceID",
    "AppleDefaultAsciiInputSource",
):
    if data.get(key) == "com.apple.keylayout.ABC":
        del data[key]

# 先完成序列化,再打开原文件写入;其他输入源和配置保持原样。
payload = plistlib.dumps(data, fmt=plistlib.FMT_BINARY, sort_keys=False)
p.write_bytes(payload)
if plistlib.loads(p.read_bytes()) != data:
    raise SystemExit("写回后的配置与预期不一致,请检查文件。")

print("已清理指定字段中的 ABC 条目,并完成写回校验。")
PY

脚本按内容寻找 ABC,避免手动删除数组下标或 XML 标签。它只删除指定字段中的 ABC 引用,不会把整个输入源列表硬改成微信输入法。原来保留的其他输入源仍然保留;如果配置本身有问题,脚本也不会替你补装或启用微信输入法。

4.3 重启前先检查真实文件

plutil -lint "$INPUT_PLIST"
plutil -p "$INPUT_PLIST"

第一条应报告 OK,第二条用于检查各输入源数组以及当前布局字段。还可以辅助搜索:

plutil -p "$INPUT_PLIST" | grep ABC
defaults read com.apple.HIToolbox | grep ABC

在读取和语法校验都成功的前提下,没有匹配通常表示没有搜到 ABC。不能把管道没有输出直接当成成功:如果前面的命令读取失败,grep 同样可能什么都不显示。磁盘内容和偏好设置读取结果若不一致,也应先查清楚。

4.4 锁定步骤与验证结果要分开看

最后一轮方案还建议在修改、校验之后锁定真实文件:

chflags uchg "$INPUT_PLIST"
ls -lO "$INPUT_PLIST"

uchg 是用户不可更改标志,设置后会阻止文件内容被修改等操作;所有者可以用 nouchg 清除它。它不是「谁都永远改不了」的锁。相关机制可参考 Apple 的文件标志说明

随后方案建议执行:

killall cfprefsd 2>/dev/null
killall SystemUIServer 2>/dev/null

再重启 Mac,检查登录后的输入源列表。

我最终确认的结果是:这次重启之后没有 ABC 了。 但记录里没有逐条命令的执行日志,也没有只改文件、不锁定的对照实验。因此可以记录这一轮处理成功,不能把成功单独归因于锁文件,更不能证明所有 macOS 环境都必须锁定。

至于最初「使用中自动切回 ABC」的问题,还需要日常使用观察;一次重启后的输入源列表,不能代替长期验证。

5. 锁定之后,怎么修改或恢复

锁定也可能影响正常的输入源设置保存。以后需要增删输入法,先解锁:

chflags nouchg "$HOME/Library/Preferences/com.apple.HIToolbox.plist"

修改后重新检查配置,再决定是否需要锁回去。如果需要恢复备份,在前面同一个终端会话里可以执行:

chflags nouchg "$INPUT_PLIST"
cp "$INPUT_BACKUP" "$INPUT_PLIST"
plutil -lint "$INPUT_PLIST"
killall cfprefsd 2>/dev/null
killall SystemUIServer 2>/dev/null

如果已经换了终端会话,先重新设置这两个路径变量,INPUT_BACKUP 要指向桌面上实际保存的那份备份。恢复后重启,再检查输入源。

6. 这次排查留下的经验

观察到的现象 能得出的判断
手动编辑后重启,ABC 仍然存在 这轮操作没有达到目的,原因还需要查
编辑器显示带后缀的文件名,重开后修改消失 应优先检查编辑对象和保存是否写回
直接操作真实路径后,重启不再出现 ABC 最后一轮处理达到了本次目标
没有逐项实验和写入日志 不能确定临时文件、缓存、锁定各自起了多大作用

AI 在前面把「重启后还在」解释成系统恢复,发现文件名异常后,又很容易把「一定没改到原文件」当成另一个确定答案。这两步都跳过了验证。

下次再遇到「配置怎么改都不生效」,我会先确认真实路径,修改后立即读回,再看重启后的状态。把这几个时间点的结果留住,才有依据判断改动究竟在哪一步丢了。