シェルでは Ctrl+W は「カーソル直前の単語を削除」だ。ブラウザやエディタでは「タブやウィンドウを閉じる」だ。手が覚えているのは前者なので、Chrome の入力欄で打つと書いていたものが消える。Ctrl+Shift+T でタブは戻るが、入力途中のテキストは戻らないことがある。
今さらだが、全部まとめて封印した。
方針
OS レベルで Ctrl+W を Ctrl+Backspace(単語削除)に置き換える。常駐ツールでキーを差し替えるので、Chrome でも Explorer でも Notion でも、アプリごとの設定に関係なく効く。
例外はターミナルだけにする。ターミナルの中では Ctrl+W はもともと単語削除として動いていて困っていないし、置き換えると逆に挙動が悪くなるので、そこだけ避ける。
アプリ側に設定があるものは先にそれで済ませて、設定を持っていないアプリ(Chrome がそうだ)のために常駐ツールを入れる、という順番になる。
1. Windows Terminal
settings.json の keybindings に "id": null を入れると、そのキーはアプリ側で処理されず、中のシェルへ素通りする。
{ "id": null, "keys": "ctrl+w" }
2. VS Code
close 系の割り当てを - で解除して、文字を入力しているときは単語削除に振る。最後の 1 行は統合ターミナルには効かないので、ターミナルの中では今までどおり単語削除として動く。
%APPDATA%\Code\User\keybindings.json:
[
{ "key": "ctrl+w", "command": "-workbench.action.closeActiveEditor" },
{ "key": "ctrl+w", "command": "-workbench.action.closeWindow" },
{ "key": "ctrl+w", "command": "-workbench.action.closeGroup" },
{ "key": "ctrl+w", "command": "deleteWordLeft", "when": "textInputFocus && !editorReadonly" }
]
保存した瞬間から効く。再起動は要らない。
3. AutoHotkey v2 を入れる
winget install --id AutoHotkey.AutoHotkey --source winget `
--accept-package-agreements --accept-source-agreements
入ったのは 2.0.28。実行ファイルは C:\Program Files ではなく %LOCALAPPDATA%\Programs\AutoHotkey\v2\AutoHotkey64.exe に置かれる。次のショートカット作成でパスを間違えたので書いておく。
4. スクリプト
~/.config/ahk/no-ctrl-w.ahk:
#Requires AutoHotkey v2.0
#SingleInstance Force
; Ctrl+W -> Ctrl+Backspace(カーソル直前の単語を削除)
; ターミナル系は除外(そこでは Ctrl+W が本来の単語削除として動くため)
ShouldRemap() {
static skip := "|windowsterminal.exe|openconsole.exe|conhost.exe|cmd.exe"
. "|powershell.exe|pwsh.exe|alacritty.exe|wezterm-gui.exe"
. "|mintty.exe|kitty.exe|tabby.exe|hyper.exe|putty.exe|"
try
exe := StrLower(ProcessGetName(WinGetPID("A")))
catch
return false
return !InStr(skip, "|" exe "|")
}
#HotIf ShouldRemap()
^w::Send("^{Backspace}")
#HotIf
; エスケープハッチ: 意図して閉じたいときだけ本来の Ctrl+W を送る
^!w::Send("^w")
いま前面にあるアプリの名前を見て、除外リストに載っていなければ Ctrl+W を Ctrl+Backspace に差し替える。それだけの内容だ。除外リストに当たったアプリでは何もしないので、Ctrl+W はそのままアプリに届く。
5. 自動起動
スタートアップフォルダにショートカットを置くだけ。
$exe = Join-Path $env:LOCALAPPDATA 'Programs\AutoHotkey\v2\AutoHotkey64.exe'
$script = Join-Path $HOME '.config\ahk\no-ctrl-w.ahk'
$lnk = Join-Path ([Environment]::GetFolderPath('Startup')) 'no-ctrl-w.lnk'
$ws = New-Object -ComObject WScript.Shell
$s = $ws.CreateShortcut($lnk)
$s.TargetPath = $exe
$s.Arguments = "`"$script`""
$s.WorkingDirectory = Split-Path $script
$s.Save()
Start-Process -FilePath $exe -ArgumentList "`"$script`""
タスクトレイに緑のアイコンが出れば動いている。
結果と使い勝手
| 対象 | 手段 |
|---|---|
| Chrome / Explorer / Notion / Obsidian ほか全部 | AutoHotkey で Ctrl+W → Ctrl+Backspace |
| VS Code | keybindings.json で close 系を解除 |
| Windows Terminal | settings.json で ctrl+w を無効化してシェルに渡す |
- 意図して閉じたいとき: Ctrl+Alt+W、またはアプリ標準の Ctrl+F4
- 効きすぎるアプリが出てきたら
skipにそのアプリの名前を足して、トレイアイコン右クリック → Reload Script - やめるとき: スタートアップの
no-ctrl-w.lnkを消す
残っている穴
- 管理者権限で動いているウィンドウには効かない。 そこでも封印したいなら、AutoHotkey 側も管理者で動かす必要がある。
- Ctrl+Backspace で単語削除ができないアプリでは、Ctrl+W が何も起きないキーになる。 単語は消えないが、閉じないという目的は達成されるので放置した。