Update to the new winit keyboard API

The main highlight of this update is that alacritty will now use new
keyboard API from the winit, which resolves a lot of issues around
key bindings, such as ability to bind dead keys. It also fixes long
standing issues with the virtual key code bindings and make bindings
in general more predictable. It also makes our default Vi key bindings
fully working.

Given that alacritty was using `VirtualKey` directly in the bindings
from the winit, and winit simply removed the enum, we've added internal
conversions to minimize the fallout, but new way to specify the bindings
should be more intuitive.

Other part of this update fixes some forward compatibility bugs with the
Wayland backend, given that wayland-rs 0.30 is fully forward compatible.
The update also fixes weird Maximized startup issues on GNOME Wayland,
however they were present on any sane compositor.

Fixes #6842.
Fixes #6455.
Fixes #6184.
Fixes #5684.
Fixes #3574.
Fixes #3460.
Fixes #1336.
Fixes #892.
Fixes #458.
Fixes #55.
This commit is contained in:
Kirill Chibisov 2023-07-11 02:22:14 +00:00 committed by GitHub
parent 09c4471b4c
commit db903503df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 763 additions and 636 deletions

View File

@ -17,6 +17,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Warnings for unused configuration file options - Warnings for unused configuration file options
- Config option `persist` in `hints` config section - Config option `persist` in `hints` config section
- Support for dynamically loading conpty.dll on Windows - Support for dynamically loading conpty.dll on Windows
- Support for keybindings with dead keys
- `Back`/`Forward` mouse buttons support in bindings
### Changed ### Changed
@ -29,6 +31,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Deprecated config option `key_bindings`, use `keyboard.bindings` - Deprecated config option `key_bindings`, use `keyboard.bindings`
- Deprecated config option `mouse_bindings`, use `mouse.bindings` - Deprecated config option `mouse_bindings`, use `mouse.bindings`
- The default colorscheme is now based on base16 classic dark - The default colorscheme is now based on base16 classic dark
- IME popup now tries to not obscure the current cursor line
### Fixed
- Unconditional query of xdg-portal settings on Wayland
- `Maximized` startup mode not filling the screen properly on GNOME Wayland
- `OptionAsAlt` with `OnlyLeft`/`OnlyRight` settings not working properly on macOS
- Default Vi key bindings for `Last`/`First` actions not working on X11/Wayland
### Removed ### Removed

285
Cargo.lock generated
View File

@ -40,7 +40,7 @@ dependencies = [
"serde_yaml", "serde_yaml",
"toml 0.7.4", "toml 0.7.4",
"unicode-width", "unicode-width",
"wayland-client", "wayland-client 0.29.5",
"windows-sys 0.48.0", "windows-sys 0.48.0",
"winit", "winit",
"x11-dl", "x11-dl",
@ -184,6 +184,12 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "atomic-waker"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -523,6 +529,15 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "cursor-icon"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "740bb192a8e2d1350119916954f4409ee7f62f149b536911eeb78ba5a20526bf"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "5.0.1" version = "5.0.1"
@ -897,9 +912,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
] ]
[[package]] [[package]]
@ -957,9 +969,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.63" version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1108,6 +1120,15 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "memoffset"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -1261,7 +1282,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"memoffset", "memoffset 0.6.5",
] ]
[[package]] [[package]]
@ -1274,7 +1295,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"memoffset", "memoffset 0.6.5",
] ]
[[package]] [[package]]
@ -1286,6 +1307,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"memoffset 0.7.1",
"static_assertions", "static_assertions",
] ]
@ -1506,6 +1528,15 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "quick-xml"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.28" version = "1.0.28"
@ -1617,14 +1648,13 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "sctk-adwaita" name = "sctk-adwaita"
version = "0.5.4" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" checksum = "2704a44480b79e10d2185d1d246e86b02e177e33bdaaaab3b1f65fdf13771448"
dependencies = [ dependencies = [
"crossfont", "crossfont",
"log", "log",
"memmap2", "smithay-client-toolkit 0.17.0",
"smithay-client-toolkit",
"tiny-skia", "tiny-skia",
] ]
@ -1775,16 +1805,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"calloop",
"dlib", "dlib",
"lazy_static", "lazy_static",
"log", "log",
"memmap2", "memmap2",
"nix 0.24.3", "nix 0.24.3",
"pkg-config", "pkg-config",
"wayland-client", "wayland-client 0.29.5",
"wayland-cursor", "wayland-cursor 0.29.5",
"wayland-protocols", "wayland-protocols 0.29.5",
]
[[package]]
name = "smithay-client-toolkit"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1476c3d89bb67079264b88aaf4f14358353318397e083b7c4e8c14517f55de7"
dependencies = [
"bitflags 1.3.2",
"calloop",
"dlib",
"lazy_static",
"log",
"memmap2",
"nix 0.26.2",
"thiserror",
"wayland-backend",
"wayland-client 0.30.2",
"wayland-cursor 0.30.0",
"wayland-protocols 0.30.0",
"wayland-protocols-wlr",
"wayland-scanner 0.30.1",
] ]
[[package]] [[package]]
@ -1793,8 +1844,17 @@ version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8"
dependencies = [ dependencies = [
"smithay-client-toolkit", "smithay-client-toolkit 0.16.0",
"wayland-client", "wayland-client 0.29.5",
]
[[package]]
name = "smol_str"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c"
dependencies = [
"serde",
] ]
[[package]] [[package]]
@ -1873,7 +1933,6 @@ dependencies = [
"arrayvec", "arrayvec",
"bytemuck", "bytemuck",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"png",
"tiny-skia-path", "tiny-skia-path",
] ]
@ -1937,6 +1996,12 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.10" version = "0.1.10"
@ -2021,9 +2086,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.86" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -2031,9 +2096,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.86" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
@ -2045,10 +2110,22 @@ dependencies = [
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-futures"
version = "0.2.86" version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -2056,9 +2133,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.86" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2069,9 +2146,24 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.86" version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "wayland-backend"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8"
dependencies = [
"cc",
"downcast-rs",
"io-lifetimes",
"nix 0.26.2",
"scoped-tls",
"smallvec",
"wayland-sys 0.30.1",
]
[[package]] [[package]]
name = "wayland-client" name = "wayland-client"
@ -2085,10 +2177,23 @@ dependencies = [
"nix 0.24.3", "nix 0.24.3",
"scoped-tls", "scoped-tls",
"wayland-commons", "wayland-commons",
"wayland-scanner", "wayland-scanner 0.29.5",
"wayland-sys 0.29.5", "wayland-sys 0.29.5",
] ]
[[package]]
name = "wayland-client"
version = "0.30.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8"
dependencies = [
"bitflags 1.3.2",
"calloop",
"nix 0.26.2",
"wayland-backend",
"wayland-scanner 0.30.1",
]
[[package]] [[package]]
name = "wayland-commons" name = "wayland-commons"
version = "0.29.5" version = "0.29.5"
@ -2108,7 +2213,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
dependencies = [ dependencies = [
"nix 0.24.3", "nix 0.24.3",
"wayland-client", "wayland-client 0.29.5",
"xcursor",
]
[[package]]
name = "wayland-cursor"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d0c3a0d5b4b688b07b0442362d3ed6bf04724fcc16cd69ab6285b90dbc487aa"
dependencies = [
"nix 0.26.2",
"wayland-client 0.30.2",
"xcursor", "xcursor",
] ]
@ -2119,9 +2235,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"wayland-client", "wayland-client 0.29.5",
"wayland-commons", "wayland-commons",
"wayland-scanner", "wayland-scanner 0.29.5",
]
[[package]]
name = "wayland-protocols"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fefbeb8a360abe67ab7c2efe1d297a1a50ee011f5460791bc18870c26bb84e2"
dependencies = [
"bitflags 1.3.2",
"wayland-backend",
"wayland-client 0.30.2",
"wayland-scanner 0.30.1",
]
[[package]]
name = "wayland-protocols-wlr"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce991093320e4a6a525876e6b629ab24da25f9baef0c2e0080ad173ec89588a"
dependencies = [
"bitflags 1.3.2",
"wayland-backend",
"wayland-client 0.30.2",
"wayland-protocols 0.30.0",
"wayland-scanner 0.30.1",
] ]
[[package]] [[package]]
@ -2135,6 +2276,17 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "wayland-scanner"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e"
dependencies = [
"proc-macro2",
"quick-xml",
"quote",
]
[[package]] [[package]]
name = "wayland-sys" name = "wayland-sys"
version = "0.29.5" version = "0.29.5"
@ -2160,14 +2312,25 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.63" version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "web-time"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19353897b48e2c4d849a2d73cb0aeb16dc2be4e00c565abfc11eb65a806e47de"
dependencies = [
"js-sys",
"once_cell",
"wasm-bindgen",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.8" version = "0.2.8"
@ -2354,21 +2517,26 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]] [[package]]
name = "winit" name = "winit"
version = "0.28.6" version = "0.29.0-beta.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "866db3f712fffba75d31bf0cdecf357c8aeafd158c5b7ab51dba2a2b2d47f196" checksum = "2f1afaf8490cc3f1309520ebb53a4cd3fc3642c7df8064a4b074bb9867998d44"
dependencies = [ dependencies = [
"android-activity", "android-activity",
"bitflags 1.3.2", "atomic-waker",
"bitflags 2.3.1",
"calloop",
"cfg_aliases", "cfg_aliases",
"core-foundation", "core-foundation",
"core-graphics", "core-graphics",
"cursor-icon",
"dispatch", "dispatch",
"instant", "fnv",
"js-sys",
"libc", "libc",
"log", "log",
"mio 0.8.8", "memmap2",
"ndk", "ndk",
"ndk-sys",
"objc2", "objc2",
"once_cell", "once_cell",
"orbclient", "orbclient",
@ -2377,15 +2545,19 @@ dependencies = [
"redox_syscall 0.3.5", "redox_syscall 0.3.5",
"sctk-adwaita", "sctk-adwaita",
"serde", "serde",
"smithay-client-toolkit", "smithay-client-toolkit 0.17.0",
"smol_str",
"unicode-segmentation",
"wasm-bindgen", "wasm-bindgen",
"wayland-client", "wasm-bindgen-futures",
"wayland-commons", "wayland-backend",
"wayland-protocols", "wayland-client 0.30.2",
"wayland-scanner", "wayland-protocols 0.30.0",
"web-sys", "web-sys",
"windows-sys 0.45.0", "web-time",
"windows-sys 0.48.0",
"x11-dl", "x11-dl",
"xkbcommon-dl",
] ]
[[package]] [[package]]
@ -2485,6 +2657,25 @@ dependencies = [
"home", "home",
] ]
[[package]]
name = "xkbcommon-dl"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "640e2c59cabea03b04fb0a34ca0fa7caaa1a50f7e588776fcda43a6a8ca28165"
dependencies = [
"bitflags 2.3.1",
"dlib",
"log",
"once_cell",
"xkeysym",
]
[[package]]
name = "xkeysym"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621"
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"
version = "0.8.14" version = "0.8.14"

View File

@ -41,7 +41,7 @@ serde_json = "1"
serde_yaml = "0.8" serde_yaml = "0.8"
toml = "0.7.1" toml = "0.7.1"
unicode-width = "0.1" unicode-width = "0.1"
winit = { version = "0.28.2", default-features = false, features = ["serde"] } winit = { version = "0.29.0-beta.0", default-features = false, features = ["serde"] }
[build-dependencies] [build-dependencies]
gl_generator = "0.14.0" gl_generator = "0.14.0"

View File

@ -6,8 +6,10 @@ use bitflags::bitflags;
use serde::de::{self, Error as SerdeError, MapAccess, Unexpected, Visitor}; use serde::de::{self, Error as SerdeError, MapAccess, Unexpected, Visitor};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use toml::Value as SerdeValue; use toml::Value as SerdeValue;
use winit::event::VirtualKeyCode::*; use winit::event::MouseButton;
use winit::event::{ModifiersState, MouseButton, VirtualKeyCode}; use winit::keyboard::Key::*;
use winit::keyboard::{Key, KeyCode, KeyLocation, ModifiersState};
use winit::platform::scancode::KeyCodeExtScancode;
use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace};
@ -41,7 +43,7 @@ pub struct Binding<T> {
} }
/// Bindings that are triggered by a keyboard key. /// Bindings that are triggered by a keyboard key.
pub type KeyBinding = Binding<Key>; pub type KeyBinding = Binding<BindingKey>;
/// Bindings that are triggered by a mouse button. /// Bindings that are triggered by a mouse button.
pub type MouseBinding = Binding<MouseButton>; pub type MouseBinding = Binding<MouseButton>;
@ -309,32 +311,11 @@ pub enum MouseAction {
} }
macro_rules! bindings { macro_rules! bindings {
(
KeyBinding;
$(
$key:ident
$(,$mods:expr)*
$(,+$mode:expr)*
$(,~$notmode:expr)*
;$action:expr
);*
$(;)*
) => {{
bindings!(
KeyBinding;
$(
Key::Keycode($key)
$(,$mods)*
$(,+$mode)*
$(,~$notmode)*
;$action
);*
)
}};
( (
$ty:ident; $ty:ident;
$( $(
$key:expr $key:expr
$(=>$location:expr)?
$(,$mods:expr)* $(,$mods:expr)*
$(,+$mode:expr)* $(,+$mode:expr)*
$(,~$notmode:expr)* $(,~$notmode:expr)*
@ -353,7 +334,7 @@ macro_rules! bindings {
$(_notmode.insert($notmode);)* $(_notmode.insert($notmode);)*
v.push($ty { v.push($ty {
trigger: $key, trigger: trigger!($ty, $key, $($location)?),
mods: _mods, mods: _mods,
mode: _mode, mode: _mode,
notmode: _notmode, notmode: _notmode,
@ -365,199 +346,147 @@ macro_rules! bindings {
}}; }};
} }
macro_rules! trigger {
(KeyBinding, $key:literal, $location:expr) => {{
BindingKey::Keycode { key: Character($key.into()), location: $location }
}};
(KeyBinding, $key:literal,) => {{
BindingKey::Keycode { key: Character($key.into()), location: KeyLocation::Standard }
}};
(KeyBinding, $key:expr,) => {{
BindingKey::Keycode { key: $key, location: KeyLocation::Standard }
}};
($ty:ident, $key:expr,) => {{
$key
}};
}
pub fn default_mouse_bindings() -> Vec<MouseBinding> { pub fn default_mouse_bindings() -> Vec<MouseBinding> {
bindings!( bindings!(
MouseBinding; MouseBinding;
MouseButton::Right; MouseAction::ExpandSelection; MouseButton::Right; MouseAction::ExpandSelection;
MouseButton::Right, ModifiersState::CTRL; MouseAction::ExpandSelection; MouseButton::Right, ModifiersState::CONTROL; MouseAction::ExpandSelection;
MouseButton::Middle, ~BindingMode::VI; Action::PasteSelection; MouseButton::Middle, ~BindingMode::VI; Action::PasteSelection;
) )
} }
pub fn default_key_bindings() -> Vec<KeyBinding> { pub fn default_key_bindings() -> Vec<KeyBinding> {
let mut bindings = bindings!( let mut bindings = bindings!(
KeyBinding; KeyBinding;
Copy; Action::Copy; Copy; Action::Copy;
Copy, +BindingMode::VI; Action::ClearSelection; Copy, +BindingMode::VI; Action::ClearSelection;
Paste, ~BindingMode::VI; Action::Paste; Paste, ~BindingMode::VI; Action::Paste;
L, ModifiersState::CTRL; Action::ClearLogNotice; "l", ModifiersState::CONTROL; Action::ClearLogNotice;
L, ModifiersState::CTRL, ~BindingMode::VI, ~BindingMode::SEARCH; "l", ModifiersState::CONTROL, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x0c".into());
Action::Esc("\x0c".into()); Tab, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[Z".into());
Tab, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; Backspace, ModifiersState::ALT, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b\x7f".into());
Action::Esc("\x1b[Z".into()); Backspace, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x7f".into());
Back, ModifiersState::ALT, ~BindingMode::VI, ~BindingMode::SEARCH; Home, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollToTop;
Action::Esc("\x1b\x7f".into()); End, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollToBottom;
Back, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; PageUp, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollPageUp;
Action::Esc("\x7f".into()); PageDown, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollPageDown;
Home, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollToTop; Home, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[1;2H".into());
End, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollToBottom; End, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[1;2F".into());
PageUp, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollPageUp; PageUp, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[5;2~".into());
PageDown, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollPageDown; PageDown, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[6;2~".into());
Home, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, Home, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOH".into());
~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[1;2H".into()); Home, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[H".into());
End, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, End, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOF".into());
~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[1;2F".into()); End, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[F".into());
PageUp, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, ArrowUp, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOA".into());
~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[5;2~".into()); ArrowUp, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[A".into());
PageDown, ModifiersState::SHIFT, +BindingMode::ALT_SCREEN, ArrowDown, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOB".into());
~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[6;2~".into()); ArrowDown, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[B".into());
Home, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; ArrowRight, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOC".into());
Action::Esc("\x1bOH".into()); ArrowRight, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[C".into());
Home, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; ArrowLeft, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOD".into());
Action::Esc("\x1b[H".into()); ArrowLeft, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[D".into());
End, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Backspace, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x7f".into());
Action::Esc("\x1bOF".into()); Insert, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[2~".into());
End, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Delete, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[3~".into());
Action::Esc("\x1b[F".into()); PageUp, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[5~".into());
Up, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; PageDown, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[6~".into());
Action::Esc("\x1bOA".into()); F1, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOP".into());
Up, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F2, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOQ".into());
Action::Esc("\x1b[A".into()); F3, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOR".into());
Down, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F4, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOS".into());
Action::Esc("\x1bOB".into()); F5, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[15~".into());
Down, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F6, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[17~".into());
Action::Esc("\x1b[B".into()); F7, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[18~".into());
Right, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F8, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[19~".into());
Action::Esc("\x1bOC".into()); F9, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[20~".into());
Right, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F10, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[21~".into());
Action::Esc("\x1b[C".into()); F11, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[23~".into());
Left, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F12, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[24~".into());
Action::Esc("\x1bOD".into()); F13, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[25~".into());
Left, ~BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; F14, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[26~".into());
Action::Esc("\x1b[D".into()); F15, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[28~".into());
Back, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x7f".into()); F16, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[29~".into());
Insert, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[2~".into()); F17, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[31~".into());
Delete, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[3~".into()); F18, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[32~".into());
PageUp, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[5~".into()); F19, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[33~".into());
PageDown, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[6~".into()); F20, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[34~".into());
F1, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOP".into());
F2, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOQ".into()); // Vi mode.
F3, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOR".into()); Space, ModifiersState::SHIFT | ModifiersState::CONTROL, ~BindingMode::SEARCH; Action::ToggleViMode;
F4, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOS".into()); Space, ModifiersState::SHIFT | ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToBottom;
F5, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[15~".into()); Escape, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection;
F6, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[17~".into()); "i", +BindingMode::VI, ~BindingMode::SEARCH; Action::ToggleViMode;
F7, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[18~".into()); "i", +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToBottom;
F8, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[19~".into()); "c", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ToggleViMode;
F9, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[20~".into()); "y", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollLineUp;
F10, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[21~".into()); "e", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollLineDown;
F11, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[23~".into()); "g", +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToTop;
F12, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[24~".into()); "g", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToBottom;
F13, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[25~".into()); "b", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollPageUp;
F14, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[26~".into()); "f", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollPageDown;
F15, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[28~".into()); "u", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollHalfPageUp;
F16, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[29~".into()); "d", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollHalfPageDown;
F17, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[31~".into()); "y", +BindingMode::VI, ~BindingMode::SEARCH; Action::Copy;
F18, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[32~".into()); "y", +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection;
F19, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[33~".into()); "/", +BindingMode::VI, ~BindingMode::SEARCH; Action::SearchForward;
F20, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[34~".into()); "/", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::SearchBackward;
NumpadEnter, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\n".into()); "v", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleNormalSelection;
Space, ModifiersState::SHIFT | ModifiersState::CTRL, ~BindingMode::SEARCH; "v", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleLineSelection;
Action::ToggleViMode; "v", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleBlockSelection;
Space, ModifiersState::SHIFT | ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; "v", ModifiersState::ALT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleSemanticSelection;
Action::ScrollToBottom; "n", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::SearchNext;
Escape, +BindingMode::VI, ~BindingMode::SEARCH; "n", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::SearchPrevious;
Action::ClearSelection; Enter, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::Open;
I, +BindingMode::VI, ~BindingMode::SEARCH; "z", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::CenterAroundViCursor;
Action::ToggleViMode; "k", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Up;
I, +BindingMode::VI, ~BindingMode::SEARCH; "j", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Down;
Action::ScrollToBottom; "h", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Left;
C, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; "l", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Right;
Action::ToggleViMode; ArrowUp, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Up;
Y, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; ArrowDown, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Down;
Action::ScrollLineUp; ArrowLeft, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Left;
E, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; ArrowRight, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Right;
Action::ScrollLineDown; "0", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::First;
G, +BindingMode::VI, ~BindingMode::SEARCH; "4", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Last;
Action::ScrollToTop; "6", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::FirstOccupied;
G, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; "H", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::High;
Action::ScrollToBottom; "M", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Middle;
B, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; "L", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Low;
Action::ScrollPageUp; "b", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::SemanticLeft;
F, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; "w", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::SemanticRight;
Action::ScrollPageDown; "e", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::SemanticRightEnd;
U, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; "b", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordLeft;
Action::ScrollHalfPageUp; "w", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordRight;
D, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; "e", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordRightEnd;
Action::ScrollHalfPageDown; "5", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Bracket;
Y, +BindingMode::VI, ~BindingMode::SEARCH; Action::Copy; Enter, +BindingMode::VI, +BindingMode::SEARCH; SearchAction::SearchConfirm;
Y, +BindingMode::VI, ~BindingMode::SEARCH; // Plain search.
Action::ClearSelection; Escape, +BindingMode::SEARCH; SearchAction::SearchCancel;
Slash, +BindingMode::VI, ~BindingMode::SEARCH; "c", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchCancel;
Action::SearchForward; "u", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchClear;
Slash, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; "w", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchDeleteWord;
Action::SearchBackward; "p", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchHistoryPrevious;
V, +BindingMode::VI, ~BindingMode::SEARCH; "n", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchHistoryNext;
ViAction::ToggleNormalSelection; ArrowUp, +BindingMode::SEARCH; SearchAction::SearchHistoryPrevious;
V, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ArrowDown, +BindingMode::SEARCH; SearchAction::SearchHistoryNext;
ViAction::ToggleLineSelection; Enter, +BindingMode::SEARCH, ~BindingMode::VI; SearchAction::SearchFocusNext;
V, ModifiersState::CTRL, +BindingMode::VI, ~BindingMode::SEARCH; Enter, ModifiersState::SHIFT, +BindingMode::SEARCH, ~BindingMode::VI; SearchAction::SearchFocusPrevious;
ViAction::ToggleBlockSelection;
V, ModifiersState::ALT, +BindingMode::VI, ~BindingMode::SEARCH;
ViAction::ToggleSemanticSelection;
N, +BindingMode::VI, ~BindingMode::SEARCH;
ViAction::SearchNext;
N, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViAction::SearchPrevious;
Return, +BindingMode::VI, ~BindingMode::SEARCH;
ViAction::Open;
Z, +BindingMode::VI, ~BindingMode::SEARCH;
ViAction::CenterAroundViCursor;
K, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Up;
J, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Down;
H, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Left;
L, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Right;
Up, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Up;
Down, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Down;
Left, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Left;
Right, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Right;
Key0, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::First;
Key4, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Last;
Key6, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::FirstOccupied;
H, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::High;
M, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Middle;
L, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Low;
B, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::SemanticLeft;
W, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::SemanticRight;
E, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::SemanticRightEnd;
B, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::WordLeft;
W, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::WordRight;
E, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::WordRightEnd;
Key5, ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH;
ViMotion::Bracket;
Return, +BindingMode::SEARCH, +BindingMode::VI;
SearchAction::SearchConfirm;
Escape, +BindingMode::SEARCH; SearchAction::SearchCancel;
C, ModifiersState::CTRL, +BindingMode::SEARCH; SearchAction::SearchCancel;
U, ModifiersState::CTRL, +BindingMode::SEARCH; SearchAction::SearchClear;
W, ModifiersState::CTRL, +BindingMode::SEARCH; SearchAction::SearchDeleteWord;
P, ModifiersState::CTRL, +BindingMode::SEARCH; SearchAction::SearchHistoryPrevious;
N, ModifiersState::CTRL, +BindingMode::SEARCH; SearchAction::SearchHistoryNext;
Up, +BindingMode::SEARCH; SearchAction::SearchHistoryPrevious;
Down, +BindingMode::SEARCH; SearchAction::SearchHistoryNext;
Return, +BindingMode::SEARCH, ~BindingMode::VI;
SearchAction::SearchFocusNext;
Return, ModifiersState::SHIFT, +BindingMode::SEARCH, ~BindingMode::VI;
SearchAction::SearchFocusPrevious;
); );
// Code Modifiers // Code Modifiers
@ -576,82 +505,52 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
ModifiersState::SHIFT, ModifiersState::SHIFT,
ModifiersState::ALT, ModifiersState::ALT,
ModifiersState::SHIFT | ModifiersState::ALT, ModifiersState::SHIFT | ModifiersState::ALT,
ModifiersState::CTRL, ModifiersState::CONTROL,
ModifiersState::SHIFT | ModifiersState::CTRL, ModifiersState::SHIFT | ModifiersState::CONTROL,
ModifiersState::ALT | ModifiersState::CTRL, ModifiersState::ALT | ModifiersState::CONTROL,
ModifiersState::SHIFT | ModifiersState::ALT | ModifiersState::CTRL, ModifiersState::SHIFT | ModifiersState::ALT | ModifiersState::CONTROL,
]; ];
for (index, mods) in modifiers.drain(..).enumerate() { for (index, mods) in modifiers.drain(..).enumerate() {
let modifiers_code = index + 2; let modifiers_code = index + 2;
bindings.extend(bindings!( bindings.extend(bindings!(
KeyBinding; KeyBinding;
Delete, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Delete, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[3;{}~", modifiers_code));
Action::Esc(format!("\x1b[3;{}~", modifiers_code)); ArrowUp, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}A", modifiers_code));
Up, mods, ~BindingMode::VI, ~BindingMode::SEARCH; ArrowDown, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}B", modifiers_code));
Action::Esc(format!("\x1b[1;{}A", modifiers_code)); ArrowRight, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}C", modifiers_code));
Down, mods, ~BindingMode::VI, ~BindingMode::SEARCH; ArrowLeft, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}D", modifiers_code));
Action::Esc(format!("\x1b[1;{}B", modifiers_code)); F1, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}P", modifiers_code));
Right, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F2, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}Q", modifiers_code));
Action::Esc(format!("\x1b[1;{}C", modifiers_code)); F3, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}R", modifiers_code));
Left, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F4, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}S", modifiers_code));
Action::Esc(format!("\x1b[1;{}D", modifiers_code)); F5, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[15;{}~", modifiers_code));
F1, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F6, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[17;{}~", modifiers_code));
Action::Esc(format!("\x1b[1;{}P", modifiers_code)); F7, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[18;{}~", modifiers_code));
F2, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F8, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[19;{}~", modifiers_code));
Action::Esc(format!("\x1b[1;{}Q", modifiers_code)); F9, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[20;{}~", modifiers_code));
F3, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F10, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[21;{}~", modifiers_code));
Action::Esc(format!("\x1b[1;{}R", modifiers_code)); F11, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[23;{}~", modifiers_code));
F4, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F12, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[24;{}~", modifiers_code));
Action::Esc(format!("\x1b[1;{}S", modifiers_code)); F13, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[25;{}~", modifiers_code));
F5, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F14, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[26;{}~", modifiers_code));
Action::Esc(format!("\x1b[15;{}~", modifiers_code)); F15, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[28;{}~", modifiers_code));
F6, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F16, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[29;{}~", modifiers_code));
Action::Esc(format!("\x1b[17;{}~", modifiers_code)); F17, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[31;{}~", modifiers_code));
F7, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F18, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[32;{}~", modifiers_code));
Action::Esc(format!("\x1b[18;{}~", modifiers_code)); F19, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[33;{}~", modifiers_code));
F8, mods, ~BindingMode::VI, ~BindingMode::SEARCH; F20, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[34;{}~", modifiers_code));
Action::Esc(format!("\x1b[19;{}~", modifiers_code));
F9, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[20;{}~", modifiers_code));
F10, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[21;{}~", modifiers_code));
F11, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[23;{}~", modifiers_code));
F12, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[24;{}~", modifiers_code));
F13, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[25;{}~", modifiers_code));
F14, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[26;{}~", modifiers_code));
F15, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[28;{}~", modifiers_code));
F16, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[29;{}~", modifiers_code));
F17, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[31;{}~", modifiers_code));
F18, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[32;{}~", modifiers_code));
F19, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[33;{}~", modifiers_code));
F20, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[34;{}~", modifiers_code));
)); ));
// We're adding the following bindings with `Shift` manually above, so skipping them here. // We're adding the following bindings with `Shift` manually above, so skipping them here.
if modifiers_code != 2 { if modifiers_code != 2 {
bindings.extend(bindings!( bindings.extend(bindings!(
KeyBinding; KeyBinding;
Insert, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Insert, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[2;{}~", modifiers_code));
Action::Esc(format!("\x1b[2;{}~", modifiers_code)); PageUp, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[5;{}~", modifiers_code));
PageUp, mods, ~BindingMode::VI, ~BindingMode::SEARCH; PageDown, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[6;{}~", modifiers_code));
Action::Esc(format!("\x1b[5;{}~", modifiers_code)); End, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}F", modifiers_code));
PageDown, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Home, mods, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc(format!("\x1b[1;{}H", modifiers_code));
Action::Esc(format!("\x1b[6;{}~", modifiers_code));
End, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[1;{}F", modifiers_code));
Home, mods, ~BindingMode::VI, ~BindingMode::SEARCH;
Action::Esc(format!("\x1b[1;{}H", modifiers_code));
)); ));
} }
} }
@ -665,21 +564,18 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
fn common_keybindings() -> Vec<KeyBinding> { fn common_keybindings() -> Vec<KeyBinding> {
bindings!( bindings!(
KeyBinding; KeyBinding;
V, ModifiersState::CTRL | ModifiersState::SHIFT, ~BindingMode::VI; Action::Paste; "c", ModifiersState::CONTROL | ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection;
C, ModifiersState::CTRL | ModifiersState::SHIFT; Action::Copy; "v", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::VI; Action::Paste;
F, ModifiersState::CTRL | ModifiersState::SHIFT, ~BindingMode::SEARCH; "f", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Action::SearchForward;
Action::SearchForward; "b", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Action::SearchBackward;
B, ModifiersState::CTRL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Insert, ModifiersState::SHIFT, ~BindingMode::VI; Action::PasteSelection;
Action::SearchBackward; "c", ModifiersState::CONTROL | ModifiersState::SHIFT; Action::Copy;
C, ModifiersState::CTRL | ModifiersState::SHIFT, "0", ModifiersState::CONTROL; Action::ResetFontSize;
+BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; "=", ModifiersState::CONTROL; Action::IncreaseFontSize;
Insert, ModifiersState::SHIFT, ~BindingMode::VI; Action::PasteSelection; "+", ModifiersState::CONTROL; Action::IncreaseFontSize;
Key0, ModifiersState::CTRL; Action::ResetFontSize; "-", ModifiersState::CONTROL; Action::DecreaseFontSize;
Equals, ModifiersState::CTRL; Action::IncreaseFontSize; "+" => KeyLocation::Numpad, ModifiersState::CONTROL; Action::IncreaseFontSize;
Plus, ModifiersState::CTRL; Action::IncreaseFontSize; "-" => KeyLocation::Numpad, ModifiersState::CONTROL; Action::DecreaseFontSize;
NumpadAdd, ModifiersState::CTRL; Action::IncreaseFontSize;
Minus, ModifiersState::CTRL; Action::DecreaseFontSize;
NumpadSubtract, ModifiersState::CTRL; Action::DecreaseFontSize;
) )
} }
@ -692,7 +588,7 @@ pub fn platform_key_bindings() -> Vec<KeyBinding> {
pub fn platform_key_bindings() -> Vec<KeyBinding> { pub fn platform_key_bindings() -> Vec<KeyBinding> {
let mut bindings = bindings!( let mut bindings = bindings!(
KeyBinding; KeyBinding;
Return, ModifiersState::ALT; Action::ToggleFullscreen; Enter, ModifiersState::ALT; Action::ToggleFullscreen;
); );
bindings.extend(common_keybindings()); bindings.extend(common_keybindings());
bindings bindings
@ -702,29 +598,27 @@ pub fn platform_key_bindings() -> Vec<KeyBinding> {
pub fn platform_key_bindings() -> Vec<KeyBinding> { pub fn platform_key_bindings() -> Vec<KeyBinding> {
bindings!( bindings!(
KeyBinding; KeyBinding;
Key0, ModifiersState::LOGO; Action::ResetFontSize; "c", ModifiersState::SUPER, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection;
Equals, ModifiersState::LOGO; Action::IncreaseFontSize; Insert, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[2;2~".into());
Plus, ModifiersState::LOGO; Action::IncreaseFontSize; "0", ModifiersState::SUPER; Action::ResetFontSize;
NumpadAdd, ModifiersState::LOGO; Action::IncreaseFontSize; "=", ModifiersState::SUPER; Action::IncreaseFontSize;
Minus, ModifiersState::LOGO; Action::DecreaseFontSize; "+", ModifiersState::SUPER; Action::IncreaseFontSize;
NumpadSubtract, ModifiersState::LOGO; Action::DecreaseFontSize; "-", ModifiersState::SUPER; Action::DecreaseFontSize;
Insert, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; "k", ModifiersState::SUPER, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x0c".into());
Action::Esc("\x1b[2;2~".into()); "k", ModifiersState::SUPER, ~BindingMode::VI, ~BindingMode::SEARCH; Action::ClearHistory;
K, ModifiersState::LOGO, ~BindingMode::VI, ~BindingMode::SEARCH; "v", ModifiersState::SUPER, ~BindingMode::VI; Action::Paste;
Action::Esc("\x0c".into()); "n", ModifiersState::SUPER; Action::CreateNewWindow;
K, ModifiersState::LOGO, ~BindingMode::VI, ~BindingMode::SEARCH; Action::ClearHistory; "f", ModifiersState::CONTROL | ModifiersState::SUPER; Action::ToggleFullscreen;
V, ModifiersState::LOGO, ~BindingMode::VI; Action::Paste; "c", ModifiersState::SUPER; Action::Copy;
N, ModifiersState::LOGO; Action::CreateNewWindow; "h", ModifiersState::SUPER; Action::Hide;
F, ModifiersState::CTRL | ModifiersState::LOGO; Action::ToggleFullscreen; "h", ModifiersState::SUPER | ModifiersState::ALT; Action::HideOtherApplications;
C, ModifiersState::LOGO; Action::Copy; "m", ModifiersState::SUPER; Action::Minimize;
C, ModifiersState::LOGO, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; "q", ModifiersState::SUPER; Action::Quit;
H, ModifiersState::LOGO; Action::Hide; "w", ModifiersState::SUPER; Action::Quit;
H, ModifiersState::LOGO | ModifiersState::ALT; Action::HideOtherApplications; "f", ModifiersState::SUPER, ~BindingMode::SEARCH; Action::SearchForward;
M, ModifiersState::LOGO; Action::Minimize; "b", ModifiersState::SUPER, ~BindingMode::SEARCH; Action::SearchBackward;
Q, ModifiersState::LOGO; Action::Quit; "+" => KeyLocation::Numpad, ModifiersState::SUPER; Action::IncreaseFontSize;
W, ModifiersState::LOGO; Action::Quit; "-" => KeyLocation::Numpad, ModifiersState::SUPER; Action::DecreaseFontSize;
F, ModifiersState::LOGO, ~BindingMode::SEARCH; Action::SearchForward;
B, ModifiersState::LOGO, ~BindingMode::SEARCH; Action::SearchBackward;
) )
} }
@ -734,23 +628,83 @@ pub fn platform_key_bindings() -> Vec<KeyBinding> {
vec![] vec![]
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Key { pub enum BindingKey {
Scancode(u32), Scancode(KeyCode),
Keycode(VirtualKeyCode), Keycode { key: Key, location: KeyLocation },
} }
impl<'a> Deserialize<'a> for Key { impl<'a> Deserialize<'a> for BindingKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'a>, D: Deserializer<'a>,
{ {
let value = SerdeValue::deserialize(deserializer)?; let value = SerdeValue::deserialize(deserializer)?;
match u32::deserialize(value.clone()) { match u32::deserialize(value.clone()) {
Ok(scancode) => Ok(Key::Scancode(scancode)), Ok(scancode) => Ok(BindingKey::Scancode(KeyCode::from_scancode(scancode))),
Err(_) => { Err(_) => {
let keycode = VirtualKeyCode::deserialize(value).map_err(D::Error::custom)?; let keycode = String::deserialize(value.clone()).map_err(D::Error::custom)?;
Ok(Key::Keycode(keycode)) let (key, location) = if keycode.chars().count() == 1 {
(Key::Character(keycode.to_lowercase().into()), KeyLocation::Standard)
} else {
// Translate legacy winit codes into their modern counterparts.
match keycode.as_str() {
"Up" => (Key::ArrowUp, KeyLocation::Standard),
"Back" => (Key::Backspace, KeyLocation::Standard),
"Down" => (Key::ArrowDown, KeyLocation::Standard),
"Left" => (Key::ArrowLeft, KeyLocation::Standard),
"Right" => (Key::ArrowRight, KeyLocation::Standard),
"At" => (Key::Character("@".into()), KeyLocation::Standard),
"Colon" => (Key::Character(":".into()), KeyLocation::Standard),
"Period" => (Key::Character(".".into()), KeyLocation::Standard),
"Return" => (Key::Enter, KeyLocation::Standard),
"LBracket" => (Key::Character("[".into()), KeyLocation::Standard),
"RBracket" => (Key::Character("]".into()), KeyLocation::Standard),
"Semicolon" => (Key::Character(";".into()), KeyLocation::Standard),
"Backslash" => (Key::Character("\\".into()), KeyLocation::Standard),
"Plus" => (Key::Character("+".into()), KeyLocation::Standard),
"Comma" => (Key::Character(",".into()), KeyLocation::Standard),
"Slash" => (Key::Character("/".into()), KeyLocation::Standard),
"Equals" => (Key::Character("=".into()), KeyLocation::Standard),
"Minus" => (Key::Character("-".into()), KeyLocation::Standard),
"Asterisk" => (Key::Character("*".into()), KeyLocation::Standard),
"Key1" => (Key::Character("1".into()), KeyLocation::Standard),
"Key2" => (Key::Character("2".into()), KeyLocation::Standard),
"Key3" => (Key::Character("3".into()), KeyLocation::Standard),
"Key4" => (Key::Character("4".into()), KeyLocation::Standard),
"Key5" => (Key::Character("5".into()), KeyLocation::Standard),
"Key6" => (Key::Character("6".into()), KeyLocation::Standard),
"Key7" => (Key::Character("7".into()), KeyLocation::Standard),
"Key8" => (Key::Character("8".into()), KeyLocation::Standard),
"Key9" => (Key::Character("9".into()), KeyLocation::Standard),
"Key0" => (Key::Character("0".into()), KeyLocation::Standard),
// Special case numpad.
"NumpadEnter" => (Key::Enter, KeyLocation::Numpad),
"NumpadAdd" => (Key::Character("+".into()), KeyLocation::Numpad),
"NumpadComma" => (Key::Character(",".into()), KeyLocation::Numpad),
"NumpadDivide" => (Key::Character("/".into()), KeyLocation::Numpad),
"NumpadEquals" => (Key::Character("=".into()), KeyLocation::Numpad),
"NumpadSubtract" => (Key::Character("-".into()), KeyLocation::Numpad),
"NumpadMultiply" => (Key::Character("*".into()), KeyLocation::Numpad),
"Numpad1" => (Key::Character("1".into()), KeyLocation::Numpad),
"Numpad2" => (Key::Character("2".into()), KeyLocation::Numpad),
"Numpad3" => (Key::Character("3".into()), KeyLocation::Numpad),
"Numpad4" => (Key::Character("4".into()), KeyLocation::Numpad),
"Numpad5" => (Key::Character("5".into()), KeyLocation::Numpad),
"Numpad6" => (Key::Character("6".into()), KeyLocation::Numpad),
"Numpad7" => (Key::Character("7".into()), KeyLocation::Numpad),
"Numpad8" => (Key::Character("8".into()), KeyLocation::Numpad),
"Numpad9" => (Key::Character("9".into()), KeyLocation::Numpad),
"Numpad0" => (Key::Character("0".into()), KeyLocation::Numpad),
_ => (
Key::deserialize(value).map_err(D::Error::custom)?,
KeyLocation::Standard,
),
}
};
Ok(BindingKey::Keycode { key, location })
}, },
} }
} }
@ -891,7 +845,7 @@ impl<'a> Deserialize<'a> for MouseButtonWrapper {
/// `KeyBinding` or `MouseBinding`. /// `KeyBinding` or `MouseBinding`.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
struct RawBinding { struct RawBinding {
key: Option<Key>, key: Option<BindingKey>,
mouse: Option<MouseButton>, mouse: Option<MouseButton>,
mods: ModifiersState, mods: ModifiersState,
mode: BindingMode, mode: BindingMode,
@ -994,7 +948,7 @@ impl<'a> Deserialize<'a> for RawBinding {
V: MapAccess<'a>, V: MapAccess<'a>,
{ {
let mut mods: Option<ModifiersState> = None; let mut mods: Option<ModifiersState> = None;
let mut key: Option<Key> = None; let mut key: Option<BindingKey> = None;
let mut chars: Option<String> = None; let mut chars: Option<String> = None;
let mut action: Option<Action> = None; let mut action: Option<Action> = None;
let mut mode: Option<BindingMode> = None; let mut mode: Option<BindingMode> = None;
@ -1014,7 +968,11 @@ impl<'a> Deserialize<'a> for RawBinding {
let value = map.next_value::<SerdeValue>()?; let value = map.next_value::<SerdeValue>()?;
match value.as_integer() { match value.as_integer() {
Some(scancode) => match u32::try_from(scancode) { Some(scancode) => match u32::try_from(scancode) {
Ok(scancode) => key = Some(Key::Scancode(scancode)), Ok(scancode) => {
key = Some(BindingKey::Scancode(KeyCode::from_scancode(
scancode,
)))
},
Err(_) => { Err(_) => {
return Err(<V::Error as Error>::custom(format!( return Err(<V::Error as Error>::custom(format!(
"Invalid key binding, scancode is too big: {}", "Invalid key binding, scancode is too big: {}",
@ -1023,7 +981,9 @@ impl<'a> Deserialize<'a> for RawBinding {
}, },
}, },
None => { None => {
key = Some(Key::deserialize(value).map_err(V::Error::custom)?); key = Some(
BindingKey::deserialize(value).map_err(V::Error::custom)?,
)
}, },
} }
}, },
@ -1196,10 +1156,10 @@ impl<'a> de::Deserialize<'a> for ModsWrapper {
let mut res = ModifiersState::empty(); let mut res = ModifiersState::empty();
for modifier in value.split('|') { for modifier in value.split('|') {
match modifier.trim().to_lowercase().as_str() { match modifier.trim().to_lowercase().as_str() {
"command" | "super" => res.insert(ModifiersState::LOGO), "command" | "super" => res.insert(ModifiersState::SUPER),
"shift" => res.insert(ModifiersState::SHIFT), "shift" => res.insert(ModifiersState::SHIFT),
"alt" | "option" => res.insert(ModifiersState::ALT), "alt" | "option" => res.insert(ModifiersState::ALT),
"control" => res.insert(ModifiersState::CTRL), "control" => res.insert(ModifiersState::CONTROL),
"none" => (), "none" => (),
_ => return Err(E::invalid_value(Unexpected::Str(modifier), &self)), _ => return Err(E::invalid_value(Unexpected::Str(modifier), &self)),
} }
@ -1217,7 +1177,7 @@ impl<'a> de::Deserialize<'a> for ModsWrapper {
mod tests { mod tests {
use super::*; use super::*;
use winit::event::ModifiersState; use winit::keyboard::ModifiersState;
type MockBinding = Binding<usize>; type MockBinding = Binding<usize>;
@ -1380,7 +1340,7 @@ mod tests {
#[test] #[test]
fn binding_trigger_mods() { fn binding_trigger_mods() {
let binding = MockBinding { let binding = MockBinding {
mods: ModifiersState::ALT | ModifiersState::LOGO, mods: ModifiersState::ALT | ModifiersState::SUPER,
..MockBinding::default() ..MockBinding::default()
}; };

View File

@ -26,7 +26,7 @@ mod mouse;
use crate::cli::Options; use crate::cli::Options;
pub use crate::config::bindings::{ pub use crate::config::bindings::{
Action, Binding, BindingMode, Key, MouseAction, SearchAction, ViAction, Action, Binding, BindingKey, BindingMode, MouseAction, SearchAction, ViAction,
}; };
#[cfg(test)] #[cfg(test)]
pub use crate::config::mouse::Mouse; pub use crate::config::mouse::Mouse;

View File

@ -7,7 +7,7 @@ use log::{error, warn};
use serde::de::{Error as SerdeError, MapAccess, Visitor}; use serde::de::{Error as SerdeError, MapAccess, Visitor};
use serde::{self, Deserialize, Deserializer}; use serde::{self, Deserialize, Deserializer};
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use winit::event::{ModifiersState, VirtualKeyCode}; use winit::keyboard::{Key, KeyLocation, ModifiersState};
use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace};
use alacritty_terminal::config::{Config as TerminalConfig, Program, LOG_TARGET_CONFIG}; use alacritty_terminal::config::{Config as TerminalConfig, Program, LOG_TARGET_CONFIG};
@ -15,7 +15,7 @@ use alacritty_terminal::term::search::RegexSearch;
use crate::config::bell::BellConfig; use crate::config::bell::BellConfig;
use crate::config::bindings::{ use crate::config::bindings::{
self, Action, Binding, Key, KeyBinding, ModeWrapper, ModsWrapper, MouseBinding, self, Action, Binding, BindingKey, KeyBinding, ModeWrapper, ModsWrapper, MouseBinding,
}; };
use crate::config::color::Colors; use crate::config::color::Colors;
use crate::config::debug::Debug; use crate::config::debug::Debug;
@ -131,13 +131,13 @@ impl UiConfig {
}; };
for hint in &self.hints.enabled { for hint in &self.hints.enabled {
let binding = match hint.binding { let binding = match &hint.binding {
Some(binding) => binding, Some(binding) => binding,
None => continue, None => continue,
}; };
let binding = KeyBinding { let binding = KeyBinding {
trigger: binding.key, trigger: binding.key.clone(),
mods: binding.mods.0, mods: binding.mods.0,
mode: binding.mode.mode, mode: binding.mode.mode,
notmode: binding.mode.not_mode, notmode: binding.mode.not_mode,
@ -208,7 +208,7 @@ pub fn deserialize_bindings<'a, D, T>(
) -> Result<Vec<Binding<T>>, D::Error> ) -> Result<Vec<Binding<T>>, D::Error>
where where
D: Deserializer<'a>, D: Deserializer<'a>,
T: Copy + Eq, T: Clone + Eq,
Binding<T>: Deserialize<'a>, Binding<T>: Deserialize<'a>,
{ {
let values = Vec::<toml::Value>::deserialize(deserializer)?; let values = Vec::<toml::Value>::deserialize(deserializer)?;
@ -278,8 +278,11 @@ impl Default for Hints {
post_processing: true, post_processing: true,
mouse: Some(HintMouse { enabled: true, mods: Default::default() }), mouse: Some(HintMouse { enabled: true, mods: Default::default() }),
binding: Some(HintBinding { binding: Some(HintBinding {
key: Key::Keycode(VirtualKeyCode::U), key: BindingKey::Keycode {
mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CTRL), key: Key::Character("u".into()),
location: KeyLocation::Standard,
},
mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CONTROL),
mode: Default::default(), mode: Default::default(),
}), }),
}], }],
@ -454,10 +457,10 @@ impl<'de> Deserialize<'de> for HintContent {
} }
/// Binding for triggering a keyboard hint. /// Binding for triggering a keyboard hint.
#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq)] #[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct HintBinding { pub struct HintBinding {
pub key: Key, pub key: BindingKey,
#[serde(default)] #[serde(default)]
pub mods: ModsWrapper, pub mods: ModsWrapper,
#[serde(default)] #[serde(default)]

View File

@ -2,7 +2,7 @@ use std::cmp::Reverse;
use std::collections::HashSet; use std::collections::HashSet;
use std::iter; use std::iter;
use winit::event::ModifiersState; use winit::keyboard::ModifiersState;
use alacritty_terminal::grid::{BidirectionalIterator, Dimensions}; use alacritty_terminal::grid::{BidirectionalIterator, Dimensions};
use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point}; use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point};

View File

@ -15,9 +15,10 @@ use glutin::surface::{Rect as DamageRect, Surface, SwapInterval, WindowSurface};
use log::{debug, info}; use log::{debug, info};
use parking_lot::MutexGuard; use parking_lot::MutexGuard;
use raw_window_handle::RawWindowHandle;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
use winit::event::ModifiersState; use winit::keyboard::ModifiersState;
use winit::window::CursorIcon; use winit::window::CursorIcon;
use crossfont::{self, Rasterize, Rasterizer}; use crossfont::{self, Rasterize, Rasterizer};
@ -393,10 +394,7 @@ impl Display {
gl_context: NotCurrentContext, gl_context: NotCurrentContext,
config: &UiConfig, config: &UiConfig,
) -> Result<Display, Error> { ) -> Result<Display, Error> {
#[cfg(any(not(feature = "wayland"), target_os = "macos", windows))] let is_wayland = matches!(window.raw_window_handle(), RawWindowHandle::Wayland(_));
let is_wayland = false;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
let is_wayland = window.wayland_surface().is_some();
let scale_factor = window.scale_factor as f32; let scale_factor = window.scale_factor as f32;
let rasterizer = Rasterizer::new(scale_factor)?; let rasterizer = Rasterizer::new(scale_factor)?;
@ -1048,7 +1046,7 @@ impl Display {
// highlighted hint could be disrupted by the old preview. // highlighted hint could be disrupted by the old preview.
dirty = self.hint_mouse_point.map_or(false, |p| p.line != point.line); dirty = self.hint_mouse_point.map_or(false, |p| p.line != point.line);
self.hint_mouse_point = Some(point); self.hint_mouse_point = Some(point);
self.window.set_mouse_cursor(CursorIcon::Hand); self.window.set_mouse_cursor(CursorIcon::Pointer);
} else if self.highlighted_hint.is_some() { } else if self.highlighted_hint.is_some() {
self.hint_mouse_point = None; self.hint_mouse_point = None;
if term.mode().intersects(TermMode::MOUSE_MODE) && !term.mode().contains(TermMode::VI) { if term.mode().intersects(TermMode::MOUSE_MODE) && !term.mode().contains(TermMode::VI) {

View File

@ -408,7 +408,14 @@ impl Window {
let nspot_x = f64::from(size.padding_x() + point.column.0 as f32 * size.cell_width()); let nspot_x = f64::from(size.padding_x() + point.column.0 as f32 * size.cell_width());
let nspot_y = f64::from(size.padding_y() + (point.line + 1) as f32 * size.cell_height()); let nspot_y = f64::from(size.padding_y() + (point.line + 1) as f32 * size.cell_height());
self.window.set_ime_position(PhysicalPosition::new(nspot_x, nspot_y)); // Exclude the rest of the line since we edit from left to right.
let width = size.width as f64 - nspot_x;
let height = size.cell_height as f64;
self.window.set_ime_cursor_area(
PhysicalPosition::new(nspot_x, nspot_y),
PhysicalSize::new(width, height),
);
} }
/// Disable macOS window shadows. /// Disable macOS window shadows.

View File

@ -19,11 +19,11 @@ use log::{debug, error, info, warn};
use wayland_client::{Display as WaylandDisplay, EventQueue}; use wayland_client::{Display as WaylandDisplay, EventQueue};
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
use winit::event::{ use winit::event::{
ElementState, Event as WinitEvent, Ime, ModifiersState, MouseButton, StartCause, ElementState, Event as WinitEvent, Ime, Modifiers, MouseButton, StartCause,
Touch as TouchEvent, WindowEvent, Touch as TouchEvent, WindowEvent,
}; };
use winit::event_loop::{ use winit::event_loop::{
ControlFlow, DeviceEventFilter, EventLoop, EventLoopProxy, EventLoopWindowTarget, ControlFlow, DeviceEvents, EventLoop, EventLoopProxy, EventLoopWindowTarget,
}; };
use winit::platform::run_return::EventLoopExtRunReturn; use winit::platform::run_return::EventLoopExtRunReturn;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@ -191,9 +191,7 @@ pub struct ActionContext<'a, N, T> {
pub clipboard: &'a mut Clipboard, pub clipboard: &'a mut Clipboard,
pub mouse: &'a mut Mouse, pub mouse: &'a mut Mouse,
pub touch: &'a mut TouchPurpose, pub touch: &'a mut TouchPurpose,
pub received_count: &'a mut usize, pub modifiers: &'a mut Modifiers,
pub suppress_chars: &'a mut bool,
pub modifiers: &'a mut ModifiersState,
pub display: &'a mut Display, pub display: &'a mut Display,
pub message_buffer: &'a mut MessageBuffer, pub message_buffer: &'a mut MessageBuffer,
pub config: &'a UiConfig, pub config: &'a UiConfig,
@ -349,17 +347,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
} }
#[inline] #[inline]
fn received_count(&mut self) -> &mut usize { fn modifiers(&mut self) -> &mut Modifiers {
self.received_count
}
#[inline]
fn suppress_chars(&mut self) -> &mut bool {
self.suppress_chars
}
#[inline]
fn modifiers(&mut self) -> &mut ModifiersState {
self.modifiers self.modifiers
} }
@ -750,7 +738,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
fn expand_selection(&mut self) { fn expand_selection(&mut self) {
let selection_type = match self.mouse().click_state { let selection_type = match self.mouse().click_state {
ClickState::Click => { ClickState::Click => {
if self.modifiers().ctrl() { if self.modifiers().state().control_key() {
SelectionType::Block SelectionType::Block
} else { } else {
SelectionType::Simple SelectionType::Simple
@ -1304,11 +1292,10 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
self.ctx.display.pending_update.set_dimensions(size); self.ctx.display.pending_update.set_dimensions(size);
}, },
WindowEvent::KeyboardInput { input, is_synthetic: false, .. } => { WindowEvent::KeyboardInput { event, is_synthetic: false, .. } => {
self.key_input(input); self.key_input(event);
}, },
WindowEvent::ModifiersChanged(modifiers) => self.modifiers_input(modifiers), WindowEvent::ModifiersChanged(modifiers) => self.modifiers_input(modifiers),
WindowEvent::ReceivedCharacter(c) => self.received_char(c),
WindowEvent::MouseInput { state, button, .. } => { WindowEvent::MouseInput { state, button, .. } => {
self.ctx.window().set_mouse_visible(true); self.ctx.window().set_mouse_visible(true);
self.mouse_input(state, button); self.mouse_input(state, button);
@ -1507,7 +1494,7 @@ impl Processor {
let mut clipboard = Clipboard::new(); let mut clipboard = Clipboard::new();
// Disable all device events, since we don't care about them. // Disable all device events, since we don't care about them.
event_loop.set_device_event_filter(DeviceEventFilter::Always); event_loop.listen_device_events(DeviceEvents::Never);
let exit_code = event_loop.run_return(move |event, event_loop, control_flow| { let exit_code = event_loop.run_return(move |event, event_loop, control_flow| {
if self.config.debug.print_events { if self.config.debug.print_events {

View File

@ -17,12 +17,16 @@ use std::time::{Duration, Instant};
use log::debug; use log::debug;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
use winit::event::{ use winit::event::{
ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, ElementState, KeyEvent, Modifiers, MouseButton, MouseScrollDelta, Touch as TouchEvent,
Touch as TouchEvent, TouchPhase, TouchPhase,
}; };
use winit::event_loop::EventLoopWindowTarget; use winit::event_loop::EventLoopWindowTarget;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use winit::keyboard::ModifiersKeyState;
use winit::keyboard::ModifiersState;
#[cfg(target_os = "macos")]
use winit::platform::macos::{EventLoopWindowTargetExtMacOS, OptionAsAlt}; use winit::platform::macos::{EventLoopWindowTargetExtMacOS, OptionAsAlt};
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
use winit::window::CursorIcon; use winit::window::CursorIcon;
use alacritty_terminal::ansi::{ClearMode, Handler}; use alacritty_terminal::ansi::{ClearMode, Handler};
@ -35,7 +39,9 @@ use alacritty_terminal::term::{ClipboardType, Term, TermMode};
use alacritty_terminal::vi_mode::ViMotion; use alacritty_terminal::vi_mode::ViMotion;
use crate::clipboard::Clipboard; use crate::clipboard::Clipboard;
use crate::config::{Action, BindingMode, Key, MouseAction, SearchAction, UiConfig, ViAction}; use crate::config::{
Action, BindingKey, BindingMode, MouseAction, SearchAction, UiConfig, ViAction,
};
use crate::display::hint::HintMatch; use crate::display::hint::HintMatch;
use crate::display::window::Window; use crate::display::window::Window;
use crate::display::{Display, SizeInfo}; use crate::display::{Display, SizeInfo};
@ -88,9 +94,7 @@ pub trait ActionContext<T: EventListener> {
fn mouse_mut(&mut self) -> &mut Mouse; fn mouse_mut(&mut self) -> &mut Mouse;
fn mouse(&self) -> &Mouse; fn mouse(&self) -> &Mouse;
fn touch_purpose(&mut self) -> &mut TouchPurpose; fn touch_purpose(&mut self) -> &mut TouchPurpose;
fn received_count(&mut self) -> &mut usize; fn modifiers(&mut self) -> &mut Modifiers;
fn suppress_chars(&mut self) -> &mut bool;
fn modifiers(&mut self) -> &mut ModifiersState;
fn scroll(&mut self, _scroll: Scroll) {} fn scroll(&mut self, _scroll: Scroll) {}
fn window(&mut self) -> &mut Window; fn window(&mut self) -> &mut Window;
fn display(&mut self) -> &mut Display; fn display(&mut self) -> &mut Display;
@ -421,7 +425,8 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
// Don't launch URLs if mouse has moved. // Don't launch URLs if mouse has moved.
self.ctx.mouse_mut().block_hint_launcher = true; self.ctx.mouse_mut().block_hint_launcher = true;
if (lmb_pressed || rmb_pressed) && (self.ctx.modifiers().shift() || !self.ctx.mouse_mode()) if (lmb_pressed || rmb_pressed)
&& (self.ctx.modifiers().state().shift_key() || !self.ctx.mouse_mode())
{ {
self.ctx.update_selection(point, cell_side); self.ctx.update_selection(point, cell_side);
} else if cell_changed } else if cell_changed
@ -472,14 +477,14 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
// Calculate modifiers value. // Calculate modifiers value.
let mut mods = 0; let mut mods = 0;
let modifiers = self.ctx.modifiers(); let modifiers = self.ctx.modifiers().state();
if modifiers.shift() { if modifiers.shift_key() {
mods += 4; mods += 4;
} }
if modifiers.alt() { if modifiers.alt_key() {
mods += 8; mods += 8;
} }
if modifiers.ctrl() { if modifiers.control_key() {
mods += 16; mods += 16;
} }
@ -539,7 +544,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
fn on_mouse_press(&mut self, button: MouseButton) { fn on_mouse_press(&mut self, button: MouseButton) {
// Handle mouse mode. // Handle mouse mode.
if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() { if !self.ctx.modifiers().state().shift_key() && self.ctx.mouse_mode() {
self.ctx.mouse_mut().click_state = ClickState::None; self.ctx.mouse_mut().click_state = ClickState::None;
let code = match button { let code = match button {
@ -547,7 +552,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
MouseButton::Middle => 1, MouseButton::Middle => 1,
MouseButton::Right => 2, MouseButton::Right => 2,
// Can't properly report more than three buttons.. // Can't properly report more than three buttons..
MouseButton::Other(_) => return, MouseButton::Back | MouseButton::Forward | MouseButton::Other(_) => return,
}; };
self.mouse_report(code, ElementState::Pressed); self.mouse_report(code, ElementState::Pressed);
@ -591,7 +596,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
self.ctx.clear_selection(); self.ctx.clear_selection();
// Start new empty selection. // Start new empty selection.
if self.ctx.modifiers().ctrl() { if self.ctx.modifiers().state().control_key() {
self.ctx.start_selection(SelectionType::Block, point, side); self.ctx.start_selection(SelectionType::Block, point, side);
} else { } else {
self.ctx.start_selection(SelectionType::Simple, point, side); self.ctx.start_selection(SelectionType::Simple, point, side);
@ -616,13 +621,13 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} }
fn on_mouse_release(&mut self, button: MouseButton) { fn on_mouse_release(&mut self, button: MouseButton) {
if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() { if !self.ctx.modifiers().state().shift_key() && self.ctx.mouse_mode() {
let code = match button { let code = match button {
MouseButton::Left => 0, MouseButton::Left => 0,
MouseButton::Middle => 1, MouseButton::Middle => 1,
MouseButton::Right => 2, MouseButton::Right => 2,
// Can't properly report more than three buttons. // Can't properly report more than three buttons.
MouseButton::Other(_) => return, MouseButton::Back | MouseButton::Forward | MouseButton::Other(_) => return,
}; };
self.mouse_report(code, ElementState::Released); self.mouse_report(code, ElementState::Released);
return; return;
@ -705,7 +710,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
.terminal() .terminal()
.mode() .mode()
.contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL) .contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL)
&& !self.ctx.modifiers().shift() && !self.ctx.modifiers().state().shift_key()
{ {
let multiplier = f64::from(self.ctx.config().terminal_config.scrolling.multiplier); let multiplier = f64::from(self.ctx.config().terminal_config.scrolling.multiplier);
@ -870,6 +875,25 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} }
} }
/// Reset mouse cursor based on modifier and terminal state.
#[inline]
pub fn reset_mouse_cursor(&mut self) {
let mouse_state = self.cursor_state();
self.ctx.window().set_mouse_cursor(mouse_state);
}
/// Modifier state change.
pub fn modifiers_input(&mut self, modifiers: Modifiers) {
*self.ctx.modifiers() = modifiers;
// Prompt hint highlight update.
self.ctx.mouse_mut().hint_highlight_dirty = true;
// Update mouse state and check for URL change.
let mouse_state = self.cursor_state();
self.ctx.window().set_mouse_cursor(mouse_state);
}
pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) { pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) {
match button { match button {
MouseButton::Left => self.ctx.mouse_mut().left_button_state = state, MouseButton::Left => self.ctx.mouse_mut().left_button_state = state,
@ -879,7 +903,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} }
// Skip normal mouse events if the message bar has been clicked. // Skip normal mouse events if the message bar has been clicked.
if self.message_bar_cursor_state() == Some(CursorIcon::Hand) if self.message_bar_cursor_state() == Some(CursorIcon::Pointer)
&& state == ElementState::Pressed && state == ElementState::Pressed
{ {
let size = self.ctx.size_info(); let size = self.ctx.size_info();
@ -894,7 +918,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
let new_icon = match current_lines.cmp(&new_lines) { let new_icon = match current_lines.cmp(&new_lines) {
Ordering::Less => CursorIcon::Default, Ordering::Less => CursorIcon::Default,
Ordering::Equal => CursorIcon::Hand, Ordering::Equal => CursorIcon::Pointer,
Ordering::Greater => { Ordering::Greater => {
if self.ctx.mouse_mode() { if self.ctx.mouse_mode() {
CursorIcon::Default CursorIcon::Default
@ -917,139 +941,6 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} }
} }
/// Process key input.
pub fn key_input(&mut self, input: KeyboardInput) {
// IME input will be applied on commit and shouldn't trigger key bindings.
if self.ctx.display().ime.preedit().is_some() {
return;
}
// All key bindings are disabled while a hint is being selected.
if self.ctx.display().hint_state.active() {
*self.ctx.suppress_chars() = false;
return;
}
// Reset search delay when the user is still typing.
if self.ctx.search_active() {
let timer_id = TimerId::new(Topic::DelayedSearch, self.ctx.window().id());
let scheduler = self.ctx.scheduler_mut();
if let Some(timer) = scheduler.unschedule(timer_id) {
scheduler.schedule(timer.event, TYPING_SEARCH_DELAY, false, timer.id);
}
}
// Reset character suppression.
*self.ctx.suppress_chars() = false;
if let ElementState::Pressed = input.state {
*self.ctx.received_count() = 0;
self.process_key_bindings(input);
}
}
/// Modifier state change.
pub fn modifiers_input(&mut self, modifiers: ModifiersState) {
*self.ctx.modifiers() = modifiers;
// Prompt hint highlight update.
self.ctx.mouse_mut().hint_highlight_dirty = true;
// Update mouse state and check for URL change.
let mouse_state = self.cursor_state();
self.ctx.window().set_mouse_cursor(mouse_state);
}
/// Reset mouse cursor based on modifier and terminal state.
#[inline]
pub fn reset_mouse_cursor(&mut self) {
let mouse_state = self.cursor_state();
self.ctx.window().set_mouse_cursor(mouse_state);
}
/// Process a received character.
pub fn received_char(&mut self, c: char) {
let suppress_chars = *self.ctx.suppress_chars();
// Don't insert chars when we have IME running.
if self.ctx.display().ime.preedit().is_some() {
return;
}
// Handle hint selection over anything else.
if self.ctx.display().hint_state.active() && !suppress_chars {
self.ctx.hint_input(c);
return;
}
// Pass keys to search and ignore them during `suppress_chars`.
let search_active = self.ctx.search_active();
if suppress_chars || search_active || self.ctx.terminal().mode().contains(TermMode::VI) {
if search_active && !suppress_chars {
self.ctx.search_input(c);
}
return;
}
self.ctx.on_terminal_input_start();
let utf8_len = c.len_utf8();
let mut bytes = vec![0; utf8_len];
c.encode_utf8(&mut bytes[..]);
#[cfg(not(target_os = "macos"))]
let alt_send_esc = true;
// Don't send ESC when `OptionAsAlt` is used. This doesn't handle
// `Only{Left,Right}` variants due to inability to distinguish them.
#[cfg(target_os = "macos")]
let alt_send_esc = self.ctx.config().window.option_as_alt != OptionAsAlt::None;
if alt_send_esc
&& *self.ctx.received_count() == 0
&& self.ctx.modifiers().alt()
&& utf8_len == 1
{
bytes.insert(0, b'\x1b');
}
self.ctx.write_to_pty(bytes);
*self.ctx.received_count() += 1;
}
/// Attempt to find a binding and execute its action.
///
/// The provided mode, mods, and key must match what is allowed by a binding
/// for its action to be executed.
fn process_key_bindings(&mut self, input: KeyboardInput) {
let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active());
let mods = *self.ctx.modifiers();
let mut suppress_chars = None;
for i in 0..self.ctx.config().key_bindings().len() {
let binding = &self.ctx.config().key_bindings()[i];
let key = match (binding.trigger, input.virtual_keycode) {
(Key::Scancode(_), _) => Key::Scancode(input.scancode),
(_, Some(key)) => Key::Keycode(key),
_ => continue,
};
if binding.is_triggered_by(mode, mods, &key) {
// Pass through the key if any of the bindings has the `ReceiveChar` action.
*suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar;
// Binding was triggered; run the action.
binding.action.clone().execute(&mut self.ctx);
}
}
// Don't suppress char if no bindings were triggered.
*self.ctx.suppress_chars() = suppress_chars.unwrap_or(false);
}
/// Attempt to find a binding and execute its action. /// Attempt to find a binding and execute its action.
/// ///
/// The provided mode, mods, and key must match what is allowed by a binding /// The provided mode, mods, and key must match what is allowed by a binding
@ -1057,7 +948,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
fn process_mouse_bindings(&mut self, button: MouseButton) { fn process_mouse_bindings(&mut self, button: MouseButton) {
let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active()); let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active());
let mouse_mode = self.ctx.mouse_mode(); let mouse_mode = self.ctx.mouse_mode();
let mods = *self.ctx.modifiers(); let mods = self.ctx.modifiers().state();
for i in 0..self.ctx.config().mouse_bindings().len() { for i in 0..self.ctx.config().mouse_bindings().len() {
let mut binding = self.ctx.config().mouse_bindings()[i].clone(); let mut binding = self.ctx.config().mouse_bindings()[i].clone();
@ -1073,6 +964,108 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} }
} }
/// Process key input.
pub fn key_input(&mut self, key: KeyEvent) {
// IME input will be applied on commit and shouldn't trigger key bindings.
if key.state == ElementState::Released || self.ctx.display().ime.preedit().is_some() {
return;
}
let text = key.text_with_all_modifiers().unwrap_or_default();
// All key bindings are disabled while a hint is being selected.
if self.ctx.display().hint_state.active() {
for character in text.chars() {
self.ctx.hint_input(character);
}
return;
}
// Reset search delay when the user is still typing.
if self.ctx.search_active() {
let timer_id = TimerId::new(Topic::DelayedSearch, self.ctx.window().id());
let scheduler = self.ctx.scheduler_mut();
if let Some(timer) = scheduler.unschedule(timer_id) {
scheduler.schedule(timer.event, TYPING_SEARCH_DELAY, false, timer.id);
}
}
// Key bindings suppress the character input.
if self.process_key_bindings(&key) {
return;
}
if self.ctx.search_active() {
for character in text.chars() {
self.ctx.search_input(character);
}
return;
}
// Vi mode on its own doesn't have any input, the search input was done before.
if self.ctx.terminal().mode().contains(TermMode::VI) || text.is_empty() {
return;
}
self.ctx.on_terminal_input_start();
let mut bytes = Vec::with_capacity(text.len() + 1);
if self.alt_send_esc() && text.len() == 1 {
bytes.push(b'\x1b');
}
bytes.extend_from_slice(text.as_bytes());
self.ctx.write_to_pty(bytes);
}
/// Whether we should send `ESC` due to `Alt` being pressed.
#[cfg(not(target_os = "macos"))]
fn alt_send_esc(&mut self) -> bool {
self.ctx.modifiers().state().alt_key()
}
#[cfg(target_os = "macos")]
fn alt_send_esc(&mut self) -> bool {
let option_as_alt = self.ctx.config().window.option_as_alt;
option_as_alt == OptionAsAlt::Both
|| (option_as_alt == OptionAsAlt::OnlyLeft
&& self.ctx.modifiers().lalt_state() == ModifiersKeyState::Pressed)
|| (option_as_alt == OptionAsAlt::OnlyRight
&& self.ctx.modifiers().ralt_state() == ModifiersKeyState::Pressed)
}
/// Attempt to find a binding and execute its action.
///
/// The provided mode, mods, and key must match what is allowed by a binding
/// for its action to be executed.
fn process_key_bindings(&mut self, key: &KeyEvent) -> bool {
let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active());
let mods = self.ctx.modifiers().state();
// Don't suppress char if no bindings were triggered.
let mut suppress_chars = None;
for i in 0..self.ctx.config().key_bindings().len() {
let binding = &self.ctx.config().key_bindings()[i];
let key = match (&binding.trigger, &key.key_without_modifiers()) {
(BindingKey::Scancode(_), _) => BindingKey::Scancode(key.physical_key),
(_, code) => BindingKey::Keycode { key: code.clone(), location: key.location },
};
if binding.is_triggered_by(mode, mods, &key) {
// Pass through the key if any of the bindings has the `ReceiveChar` action.
*suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar;
// Binding was triggered; run the action.
binding.action.clone().execute(&mut self.ctx);
}
}
suppress_chars.unwrap_or(false)
}
/// Check mouse icon state in relation to the message bar. /// Check mouse icon state in relation to the message bar.
fn message_bar_cursor_state(&self) -> Option<CursorIcon> { fn message_bar_cursor_state(&self) -> Option<CursorIcon> {
// Since search is above the message bar, the button is offset by search's height. // Since search is above the message bar, the button is offset by search's height.
@ -1092,7 +1085,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
} else if mouse.y <= terminal_end + size.cell_height() as usize } else if mouse.y <= terminal_end + size.cell_height() as usize
&& point.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.columns() && point.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.columns()
{ {
Some(CursorIcon::Hand) Some(CursorIcon::Pointer)
} else { } else {
Some(CursorIcon::Default) Some(CursorIcon::Default)
} }
@ -1110,8 +1103,8 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
if let Some(mouse_state) = self.message_bar_cursor_state() { if let Some(mouse_state) = self.message_bar_cursor_state() {
mouse_state mouse_state
} else if self.ctx.display().highlighted_hint.as_ref().map_or(false, hint_highlighted) { } else if self.ctx.display().highlighted_hint.as_ref().map_or(false, hint_highlighted) {
CursorIcon::Hand CursorIcon::Pointer
} else if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() { } else if !self.ctx.modifiers().state().shift_key() && self.ctx.mouse_mode() {
CursorIcon::Default CursorIcon::Default
} else { } else {
CursorIcon::Text CursorIcon::Text
@ -1158,7 +1151,8 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
mod tests { mod tests {
use super::*; use super::*;
use winit::event::{DeviceId, Event as WinitEvent, VirtualKeyCode, WindowEvent}; use winit::event::{DeviceId, Event as WinitEvent, WindowEvent};
use winit::keyboard::Key;
use winit::window::WindowId; use winit::window::WindowId;
use alacritty_terminal::event::Event as TerminalEvent; use alacritty_terminal::event::Event as TerminalEvent;
@ -1166,7 +1160,7 @@ mod tests {
use crate::config::Binding; use crate::config::Binding;
use crate::message_bar::MessageBuffer; use crate::message_bar::MessageBuffer;
const KEY: VirtualKeyCode = VirtualKeyCode::Key0; const KEY: Key<&'static str> = Key::Character("0");
struct MockEventProxy; struct MockEventProxy;
impl EventListener for MockEventProxy {} impl EventListener for MockEventProxy {}
@ -1177,9 +1171,7 @@ mod tests {
pub mouse: &'a mut Mouse, pub mouse: &'a mut Mouse,
pub clipboard: &'a mut Clipboard, pub clipboard: &'a mut Clipboard,
pub message_buffer: &'a mut MessageBuffer, pub message_buffer: &'a mut MessageBuffer,
pub received_count: usize, pub modifiers: Modifiers,
pub suppress_chars: bool,
pub modifiers: ModifiersState,
config: &'a UiConfig, config: &'a UiConfig,
} }
@ -1240,15 +1232,7 @@ mod tests {
unimplemented!(); unimplemented!();
} }
fn received_count(&mut self) -> &mut usize { fn modifiers(&mut self) -> &mut Modifiers {
&mut self.received_count
}
fn suppress_chars(&mut self) -> &mut bool {
&mut self.suppress_chars
}
fn modifiers(&mut self) -> &mut ModifiersState {
&mut self.modifiers &mut self.modifiers
} }
@ -1324,8 +1308,6 @@ mod tests {
mouse: &mut mouse, mouse: &mut mouse,
size_info: &size, size_info: &size,
clipboard: &mut clipboard, clipboard: &mut clipboard,
received_count: 0,
suppress_chars: false,
modifiers: Default::default(), modifiers: Default::default(),
message_buffer: &mut message_buffer, message_buffer: &mut message_buffer,
config: &cfg, config: &cfg,
@ -1379,7 +1361,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Left, button: MouseButton::Left,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1396,7 +1377,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Right, button: MouseButton::Right,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1413,7 +1393,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Middle, button: MouseButton::Middle,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1430,7 +1409,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Left, button: MouseButton::Left,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1447,7 +1425,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Left, button: MouseButton::Left,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1464,7 +1441,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Left, button: MouseButton::Left,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1481,7 +1457,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Left, button: MouseButton::Left,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1498,7 +1473,6 @@ mod tests {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Right, button: MouseButton::Right,
device_id: unsafe { DeviceId::dummy() }, device_id: unsafe { DeviceId::dummy() },
modifiers: ModifiersState::default(),
}, },
window_id: unsafe { WindowId::dummy() }, window_id: unsafe { WindowId::dummy() },
}, },
@ -1524,10 +1498,10 @@ mod tests {
test_process_binding! { test_process_binding! {
name: process_binding_nomode_controlmod, name: process_binding_nomode_controlmod,
binding: Binding { trigger: KEY, mods: ModifiersState::CTRL, action: Action::from("\x1b[1;5D"), mode: BindingMode::empty(), notmode: BindingMode::empty() }, binding: Binding { trigger: KEY, mods: ModifiersState::CONTROL, action: Action::from("\x1b[1;5D"), mode: BindingMode::empty(), notmode: BindingMode::empty() },
triggers: true, triggers: true,
mode: BindingMode::empty(), mode: BindingMode::empty(),
mods: ModifiersState::CTRL, mods: ModifiersState::CONTROL,
} }
test_process_binding! { test_process_binding! {
@ -1564,9 +1538,9 @@ mod tests {
test_process_binding! { test_process_binding! {
name: process_binding_fail_with_extra_mods, name: process_binding_fail_with_extra_mods,
binding: Binding { trigger: KEY, mods: ModifiersState::LOGO, action: Action::from("arst"), mode: BindingMode::empty(), notmode: BindingMode::empty() }, binding: Binding { trigger: KEY, mods: ModifiersState::SUPER, action: Action::from("arst"), mode: BindingMode::empty(), notmode: BindingMode::empty() },
triggers: false, triggers: false,
mode: BindingMode::empty(), mode: BindingMode::empty(),
mods: ModifiersState::ALT | ModifiersState::LOGO, mods: ModifiersState::ALT | ModifiersState::SUPER,
} }
} }

View File

@ -21,7 +21,7 @@ use raw_window_handle::HasRawDisplayHandle;
use serde_json as json; use serde_json as json;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use wayland_client::EventQueue; use wayland_client::EventQueue;
use winit::event::{Event as WinitEvent, ModifiersState, WindowEvent}; use winit::event::{Event as WinitEvent, Modifiers, WindowEvent};
use winit::event_loop::{EventLoopProxy, EventLoopWindowTarget}; use winit::event_loop::{EventLoopProxy, EventLoopWindowTarget};
use winit::window::WindowId; use winit::window::WindowId;
@ -55,10 +55,8 @@ pub struct WindowContext {
event_queue: Vec<WinitEvent<'static, Event>>, event_queue: Vec<WinitEvent<'static, Event>>,
terminal: Arc<FairMutex<Term<EventProxy>>>, terminal: Arc<FairMutex<Term<EventProxy>>>,
cursor_blink_timed_out: bool, cursor_blink_timed_out: bool,
modifiers: ModifiersState, modifiers: Modifiers,
search_state: SearchState, search_state: SearchState,
received_count: usize,
suppress_chars: bool,
notifier: Notifier, notifier: Notifier,
font_size: Size, font_size: Size,
mouse: Mouse, mouse: Mouse,
@ -248,9 +246,7 @@ impl WindowContext {
config, config,
notifier: Notifier(loop_tx), notifier: Notifier(loop_tx),
cursor_blink_timed_out: Default::default(), cursor_blink_timed_out: Default::default(),
suppress_chars: Default::default(),
message_buffer: Default::default(), message_buffer: Default::default(),
received_count: Default::default(),
search_state: Default::default(), search_state: Default::default(),
event_queue: Default::default(), event_queue: Default::default(),
ipc_config: Default::default(), ipc_config: Default::default(),
@ -423,8 +419,6 @@ impl WindowContext {
let context = ActionContext { let context = ActionContext {
cursor_blink_timed_out: &mut self.cursor_blink_timed_out, cursor_blink_timed_out: &mut self.cursor_blink_timed_out,
message_buffer: &mut self.message_buffer, message_buffer: &mut self.message_buffer,
received_count: &mut self.received_count,
suppress_chars: &mut self.suppress_chars,
search_state: &mut self.search_state, search_state: &mut self.search_state,
modifiers: &mut self.modifiers, modifiers: &mut self.modifiers,
font_size: &mut self.font_size, font_size: &mut self.font_size,
@ -471,7 +465,7 @@ impl WindowContext {
&terminal, &terminal,
&self.config, &self.config,
&self.mouse, &self.mouse,
self.modifiers, self.modifiers.state(),
); );
self.mouse.hint_highlight_dirty = false; self.mouse.hint_highlight_dirty = false;
} }

View File

@ -14,4 +14,4 @@ serde = "1.0.163"
toml = "0.7.1" toml = "0.7.1"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
winit = { version = "0.28.2", default-features = false, features = ["serde"] } winit = { version = "0.29.0-beta.0", default-features = false, features = ["serde"] }

View File

@ -153,7 +153,7 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Alt"_ : _"Alt"_
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"ToggleSemanticSelection"_ : _"ToggleSemanticSelection"_
| _"Return"_ | _"Enter"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Open"_ : _"Open"_
@ -177,31 +177,31 @@ configuration. See *alacritty*(5) for full configuration format documentation.
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Right"_ : _"Right"_
| _"Up"_ | _"ArrowUp"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Up"_ : _"Up"_
| _"Down"_ | _"ArrowDown"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Down"_ : _"Down"_
| _"Left"_ | _"ArrowLeft"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Left"_ : _"Left"_
| _"Right"_ | _"ArrowRight"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Right"_ : _"Right"_
| _"Key0"_ | _"0"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"First"_ : _"First"_
| _"Key4"_ | _"4"_
: _"Shift"_ : _"Shift"_
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Last"_ : _"Last"_
| _"Key6"_ | _"6"_
: _"Shift"_ : _"Shift"_
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"FirstOccupied"_ : _"FirstOccupied"_
@ -241,15 +241,15 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Shift"_ : _"Shift"_
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"WordRightEnd"_ : _"WordRightEnd"_
| _"Key5"_ | _"5"_
: _"Shift"_ : _"Shift"_
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"Bracket"_ : _"Bracket"_
| _"Slash"_ | _"/"_
:[ :[
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"SearchForward"_ : _"SearchForward"_
| _"Slash"_ | _"/"_
: _"Shift"_ : _"Shift"_
: _"Vi|~Search"_ : _"Vi|~Search"_
: _"SearchBackward"_ : _"SearchBackward"_
@ -269,7 +269,7 @@ configuration. See *alacritty*(5) for full configuration format documentation.
:[ *mods* :[ *mods*
:[ *mode* :[ *mode*
:[ *action* :[ *action*
| _"Return"_ | _"Enter"_
:[ :[
: _"Search|Vi"_ : _"Search|Vi"_
: _"SearchConfirm"_ : _"SearchConfirm"_
@ -297,15 +297,15 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Control"_ : _"Control"_
: _"Search"_ : _"Search"_
: _"SearchHistoryNext"_ : _"SearchHistoryNext"_
| _"Up"_ | _"ArrowUp"_
:[ :[
: _"Search"_ : _"Search"_
: _"SearchHistoryPrevious"_ : _"SearchHistoryPrevious"_
| _"Down"_ | _"ArrowDown"_
:[ :[
: _"Search"_ : _"Search"_
: _"SearchHistoryNext"_ : _"SearchHistoryNext"_
| _"Return"_ | _"Enter"_
:[ :[
: _"Search|~Vi"_ : _"Search|~Vi"_
: _"SearchFocusNext"_ : _"SearchFocusNext"_
@ -340,15 +340,15 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Shift"_ : _"Shift"_
:[ :[
: _"PasteSelection"_ : _"PasteSelection"_
| _"Key0"_ | _"0"_
: _"Control"_ : _"Control"_
:[ :[
: _"ResetFontSize"_ : _"ResetFontSize"_
| _"Equals"_ | _"="_
: _"Control"_ : _"Control"_
:[ :[
: _"IncreaseFontSize"_ : _"IncreaseFontSize"_
| _"Plus"_ | _"+"_
: _"Control"_ : _"Control"_
:[ :[
: _"IncreaseFontSize"_ : _"IncreaseFontSize"_
@ -356,7 +356,7 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Control"_ : _"Control"_
:[ :[
: _"IncreaseFontSize"_ : _"IncreaseFontSize"_
| _"Minus"_ | _"-"_
: _"Control"_ : _"Control"_
:[ :[
: _"DecreaseFontSize"_ : _"DecreaseFontSize"_
@ -371,7 +371,7 @@ configuration. See *alacritty*(5) for full configuration format documentation.
:[ *mods* :[ *mods*
:[ *mode* :[ *mode*
:[ *action* :[ *action*
| _"Return"_ | _"Enter"_
: _"Alt"_ : _"Alt"_
:[ :[
: _"ToggleFullscreen"_ : _"ToggleFullscreen"_
@ -390,15 +390,15 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Command"_ : _"Command"_
: _"~Vi|~Search"_ : _"~Vi|~Search"_
: _"ClearHistory"_ : _"ClearHistory"_
| _"Key0"_ | _"0"_
: _"Command"_ : _"Command"_
:[ :[
: _"ResetFontSize"_ : _"ResetFontSize"_
| _"Equals"_ | _"="_
: _"Command"_ : _"Command"_
:[ :[
: _"IncreaseFontSize"_ : _"IncreaseFontSize"_
| _"Plus"_ | _"+"_
: _"Command"_ : _"Command"_
:[ :[
: _"IncreaseFontSize"_ : _"IncreaseFontSize"_
@ -406,7 +406,7 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Command"_ : _"Command"_
:[ :[
: _"IncreaseFontSize"_ : _"IncreaseFontSize"_
| _"Minus"_ | _"-"_
: _"Command"_ : _"Command"_
:[ :[
: _"DecreaseFontSize"_ : _"DecreaseFontSize"_

View File

@ -656,11 +656,14 @@ This section documents the *[keyboard]* table of the configuration file.
*key* <string> *key* <string>
Identifier of the binding's key, for example: _"A"_, _"F1"_, or The regular keys like _"A"_, _"0"_, and _"Я"_ can be mapped directly
_"Key0"_. without any special syntax. Full list of named keys like _"F1"_ and the
syntax for dead keys can be found here:++
https://docs.rs/winit/\*/winit/keyboard/enum.Key.html
A full list with available key codes can be found here:++ Numpad keys are prefixed by _Numpad_: "NumpadEnter" | "NumpadAdd" |
https://docs.rs/winit/\*/winit/event/enum.VirtualKeyCode.html#variants "NumpadComma" | "NumpadDivide" | "NumpadEquals" | "NumpadSubtract" |
"NumpadMultiply" | "Numpad[0-9]".
The _key_ field also supports using scancodes, which are specified as a The _key_ field also supports using scancodes, which are specified as a
decimal number. decimal number.