5.9 KiB
title | excerpt | date | tags | |||
---|---|---|---|---|---|---|
Mapping Ctrl+H to Backspace in terminal emulator | Also fix Ctrl+Backspace in PowerShell | 2023-07-17 |
|
A few months ago, there was an article which encouraged Linux users to use more readline keyboard shortcuts. readline keyboard shortcuts are based on Emacs keybindings, while also support switching to vi keybindings. At that time, I was only familiar with Ctrl+a
(line start) and Ctrl+e
(line end). Interested to learn more tricks, I went on search for a cheatsheet and found this. I then added two missing shortcuts (Ctrl+h
& Ctrl+d
), printed it out and stick it to my desk.
However there were two shortcuts which did not work as intended: Ctrl+h
and Ctrl+Backspace
. The first one is supposed to be equivalent to backspace, but it was deleting previous word just like Ctrl+Backspace
or Ctrl+w
. The second one did not work on PowerShell's Emacs mode.
While looking for a workaround for other terminal and shell, I find it helpful to remember these two facts so that you can stay on the right track.
- $TERM does not refer to the terminal emulator
- Shell does not recognise Ctrl+Backspace
$TERM is not the terminal emulator
In Kitty, $TERM
is "xterm-kitty"; most other Linux terminals output it as "xterm-256color". The value actually refers to the "terminfo" being used and not the terminal emulator.
Shell does not recognise Ctrl+Backspace
When Ctrl+Backspace is pressed, a terminal emulator either sends "^?" or "^H" control character to the shell, which then initiate an action (e.g. "backward-kill-word").
"^[character]" is first and foremost a caret notation of a control character, a friendlier representation of hexadecimal, much like hexadecimal is a nicer representation of binary. "^H" actually means control-code-8 (H is the eighth letter), instead of representing Ctrl+h
. "^H" can be entered using Ctrl+h
simply because it is more practical than having a dedicated key for each control character on a keyboard.
Remap Ctrl+h to ^?
Most terminal emulators map Backspace
to "^?" and Ctrl+Backspace
to "^H". Since Ctrl+h
is also mapped to "^H", thus sharing a similar action ("backward-kill-word") with Ctrl+Backspace
. The easiest fix is to remap Ctrl+h
to "^?". This approach only needs to configure the terminal emulator.
To check which control character is mapped to:
$ showkey -a
# backspace
^? 127 0177 0x7f
# ctrl+ backspace
^H 8 0010 0x08
kitty
map ctrl+h send_text normal \x7f
Add the above line to the end of "$HOME/.config/kitty/kitty.conf". "7f" is the hex of "^?".
Press Ctrl+Shirt+F5
to reload the config and run showkey -a
to verify Ctrl+h
has been remapped.
$ showkey -a
# ctrl+h
^? 127 0177 0x7f
Windows Terminal
Go Settings -> Open JSON file which will open "$home\AppData\Local\Packages\Microsoft.WindowsTerminal_xxx\LocalState\settings.json". Under "actions"
list, append the following object.
{
"command": {
"action": "sendInput",
"input": "\u007F"
},
"keys": "ctrl+h"
}
Map Ctrl+Backspace to backward-kill-word
Ctrl+Backspace
does not work as expected when I switch the PowerShell's edit mode to Emacs Set-PSReadLineOption -EditMode Emacs
, even though it works in the default Cmd
mode. This is because PowerShell binds it to BackwardDeleteChar
in Emacs mode. Somehow I could not remap it to "^H" (\b
).
Some xterm users also have this issue and a workaround is by mapping it to an unused escape sequence, then bind it to backward-kill-word in the shell. While Windows Terminal supports sending an escape sequence, the corresponding binding is not supported in PowerShell. Instead of using escape sequence, let's use a unicode character, specifically a character within the range of private use area (U+E888-U+F8FF
) to avoid conflict with existing characters. I choose U+E888
for this example.
Anyhow, it is only a tiny issue for me since I can always use Ctrl+w
.
Windows Terminal
Go Settings -> Open JSON file which will open "$home\AppData\Local\Packages\Microsoft.WindowsTerminal_xxx\LocalState\settings.json". Under "actions"
list, append the following object.
{
"command": {
"action": "sendInput",
"input": "\uE888"
},
"keys": "ctrl+backspace"
}
PowerShell
Set-PSReadLineKeyHandler -Chord "`u{E888}" -Function BackwardKillWord
The following Windows Terminal + PowerShell configs did not work for me. Windows Terminal did yield the correct control character, but somehow PowerShell could not recognise it.
{
"command": {
"action": "sendInput",
"input": "\u007F"
},
"keys": "backspace"
},
{
"command": {
"action": "sendInput",
"input": "\b"
},
"keys": "ctrl+backspace"
}
Set-PSReadLineKeyHandler -Chord "`u{007F}" -Function BackwardDeleteChar
Set-PSReadLineKeyHandler -Chord "`b" -Function BackwardKillWord
zsh
bindkey '\uE888' backward-kill-word
bash
bind '"\uE888":backward-kill-word'