mirror of https://gitlab.com/curben/blog
138 lines
5.8 KiB
Markdown
138 lines
5.8 KiB
Markdown
---
|
|
title: Mapping Ctrl+H to Backspace in terminal emulator
|
|
excerpt: Also fix Ctrl+Backspace in PowerShell
|
|
date: 2023-07-17
|
|
tags:
|
|
- linux
|
|
---
|
|
|
|
A few months ago, there was [an article](https://www.masteringemacs.org/article/keyboard-shortcuts-every-command-line-hacker-should-know-about-gnu-readline) 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](https://clementc.github.io/blog/2018/01/25/moving_cli/). I then added two missing shortcuts (`Ctrl+h` & `Ctrl+d`), printed it out and stick it to my desk.
|
|
|
|
![readline keyboard shortcuts](20230717/readline-shortcuts.png)
|
|
|
|
However there were two shortcuts which did not work as intended: `Ctrl+h` and `Ctrl+Backspace`. The first one is [supposed to](https://en.wikipedia.org/wiki/GNU_Readline#Emacs_keyboard_shortcuts) 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](https://en.wikipedia.org/wiki/Terminfo)" being used and not the [terminal emulator](https://en.wikipedia.org/wiki/Xterm).
|
|
|
|
## Shell does not recognise Ctrl+Backspace
|
|
|
|
When Ctrl+Backspace is pressed, a terminal emulator either sends "^?" or "^H" [control character](https://en.wikipedia.org/wiki/C0_and_C1_control_codes#C0_controls) to the shell, which then initiate an action (e.g. "backward-kill-word").
|
|
|
|
"^\[character\]" is first and foremost a [caret notation](https://en.wikipedia.org/wiki/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.
|
|
|
|
```json
|
|
{
|
|
"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`](https://learn.microsoft.com/en-us/powershell/module/psreadline/about/about_psreadline_functions#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](https://www.vinc17.net/unix/ctrl-backspace.en.html) to an unused escape sequence, then bind it to backward-kill-word in the shell. While Windows Terminal [supports](https://learn.microsoft.com/en-us/windows/terminal/customize-settings/actions#send-input) sending an escape sequence, the corresponding binding is [not supported](https://github.com/PowerShell/PSReadLine/issues/3430) in PowerShell. Instead of using escape sequence, let's use a unicode character, specifically a character within the range of [private use area](https://en.wikipedia.org/wiki/Private_Use_Areas) (`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.
|
|
|
|
```json
|
|
{
|
|
"command": {
|
|
"action": "sendInput",
|
|
"input": "\uE888"
|
|
},
|
|
"keys": "ctrl+backspace"
|
|
}
|
|
```
|
|
|
|
#### PowerShell
|
|
|
|
```ps $PROFILE
|
|
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.
|
|
|
|
```json
|
|
{
|
|
"command": {
|
|
"action": "sendInput",
|
|
"input": "\u007F"
|
|
},
|
|
"keys": "backspace"
|
|
},
|
|
{
|
|
"command": {
|
|
"action": "sendInput",
|
|
"input": "\b"
|
|
},
|
|
"keys": "ctrl+backspace"
|
|
}
|
|
```
|
|
|
|
```ps $PROFILE
|
|
Set-PSReadLineKeyHandler -Chord "`u{007F}" -Function BackwardDeleteChar
|
|
Set-PSReadLineKeyHandler -Chord "`b" -Function BackwardKillWord
|
|
```
|
|
|
|
#### zsh
|
|
|
|
```sh $HOME/.zshrc
|
|
bindkey '\uE888' backward-kill-word
|
|
```
|
|
|
|
#### bash
|
|
|
|
```sh $HOME/.bashrc
|
|
bind '"\uE888":backward-kill-word'
|
|
```
|