Add `ReceiveChar` action for passing key's text
This commit is contained in:
parent
87cf14a4b7
commit
fe6f1760b4
|
@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Extra bindings for F13-F20
|
- Extra bindings for F13-F20
|
||||||
- Terminal escape bindings with combined modifiers
|
- Terminal escape bindings with combined modifiers
|
||||||
- Bindings for ScrollToTop and ScrollToBottom actions
|
- Bindings for ScrollToTop and ScrollToBottom actions
|
||||||
|
- `ReceiveChar` key binding action to insert the key's text character
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -496,6 +496,7 @@ mouse_bindings:
|
||||||
# - ToggleFullscreen
|
# - ToggleFullscreen
|
||||||
# - SpawnNewInstance
|
# - SpawnNewInstance
|
||||||
# - ClearLogNotice
|
# - ClearLogNotice
|
||||||
|
# - ReceiveChar
|
||||||
# - None
|
# - None
|
||||||
#
|
#
|
||||||
# (macOS only):
|
# (macOS only):
|
||||||
|
@ -536,7 +537,8 @@ mouse_bindings:
|
||||||
#
|
#
|
||||||
# Bindings are always filled by default, but will be replaced when a new
|
# Bindings are always filled by default, but will be replaced when a new
|
||||||
# binding with the same triggers is defined. To unset a default binding, it can
|
# binding with the same triggers is defined. To unset a default binding, it can
|
||||||
# be mapped to the `None` action.
|
# be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for
|
||||||
|
# a no-op if you do not wish to receive input characters for that binding.
|
||||||
key_bindings:
|
key_bindings:
|
||||||
# (Windows/Linux only)
|
# (Windows/Linux only)
|
||||||
#- { key: V, mods: Control|Shift, action: Paste }
|
#- { key: V, mods: Control|Shift, action: Paste }
|
||||||
|
|
|
@ -269,6 +269,7 @@ where
|
||||||
{
|
{
|
||||||
let mut bindings: Vec<Binding<T>> = failure_default(deserializer)?;
|
let mut bindings: Vec<Binding<T>> = failure_default(deserializer)?;
|
||||||
|
|
||||||
|
// Remove matching default bindings
|
||||||
for binding in bindings.iter() {
|
for binding in bindings.iter() {
|
||||||
default.retain(|b| !b.triggers_match(binding));
|
default.retain(|b| !b.triggers_match(binding));
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,60 +234,60 @@ impl<T> Binding<T> {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Write an escape sequence
|
/// Write an escape sequence.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
Esc(String),
|
Esc(String),
|
||||||
|
|
||||||
/// Paste contents of system clipboard
|
/// Paste contents of system clipboard.
|
||||||
Paste,
|
Paste,
|
||||||
|
|
||||||
// Store current selection into clipboard
|
/// Store current selection into clipboard.
|
||||||
Copy,
|
Copy,
|
||||||
|
|
||||||
/// Paste contents of selection buffer
|
/// Paste contents of selection buffer.
|
||||||
PasteSelection,
|
PasteSelection,
|
||||||
|
|
||||||
/// Increase font size
|
/// Increase font size.
|
||||||
IncreaseFontSize,
|
IncreaseFontSize,
|
||||||
|
|
||||||
/// Decrease font size
|
/// Decrease font size.
|
||||||
DecreaseFontSize,
|
DecreaseFontSize,
|
||||||
|
|
||||||
/// Reset font size to the config value
|
/// Reset font size to the config value.
|
||||||
ResetFontSize,
|
ResetFontSize,
|
||||||
|
|
||||||
/// Scroll exactly one page up
|
/// Scroll exactly one page up.
|
||||||
ScrollPageUp,
|
ScrollPageUp,
|
||||||
|
|
||||||
/// Scroll exactly one page down
|
/// Scroll exactly one page down.
|
||||||
ScrollPageDown,
|
ScrollPageDown,
|
||||||
|
|
||||||
/// Scroll one line up
|
/// Scroll one line up.
|
||||||
ScrollLineUp,
|
ScrollLineUp,
|
||||||
|
|
||||||
/// Scroll one line down
|
/// Scroll one line down.
|
||||||
ScrollLineDown,
|
ScrollLineDown,
|
||||||
|
|
||||||
/// Scroll all the way to the top
|
/// Scroll all the way to the top.
|
||||||
ScrollToTop,
|
ScrollToTop,
|
||||||
|
|
||||||
/// Scroll all the way to the bottom
|
/// Scroll all the way to the bottom.
|
||||||
ScrollToBottom,
|
ScrollToBottom,
|
||||||
|
|
||||||
/// Clear the display buffer(s) to remove history
|
/// Clear the display buffer(s) to remove history.
|
||||||
ClearHistory,
|
ClearHistory,
|
||||||
|
|
||||||
/// Run given command
|
/// Run given command.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
Command(String, Vec<String>),
|
Command(String, Vec<String>),
|
||||||
|
|
||||||
/// Hides the Alacritty window
|
/// Hide the Alacritty window.
|
||||||
Hide,
|
Hide,
|
||||||
|
|
||||||
/// Quits Alacritty.
|
/// Quit Alacritty.
|
||||||
Quit,
|
Quit,
|
||||||
|
|
||||||
/// Clears warning and error notices.
|
/// Clear warning and error notices.
|
||||||
ClearLogNotice,
|
ClearLogNotice,
|
||||||
|
|
||||||
/// Spawn a new instance of Alacritty.
|
/// Spawn a new instance of Alacritty.
|
||||||
|
@ -300,6 +300,9 @@ pub enum Action {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
ToggleSimpleFullscreen,
|
ToggleSimpleFullscreen,
|
||||||
|
|
||||||
|
/// Allow receiving char input.
|
||||||
|
ReceiveChar,
|
||||||
|
|
||||||
/// No action.
|
/// No action.
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
@ -389,7 +392,7 @@ impl Action {
|
||||||
Action::SpawnNewInstance => {
|
Action::SpawnNewInstance => {
|
||||||
ctx.spawn_new_instance();
|
ctx.spawn_new_instance();
|
||||||
},
|
},
|
||||||
Action::None => (),
|
Action::ReceiveChar | Action::None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,7 +717,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
self.copy_selection();
|
self.copy_selection();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn URL launcher when clicking on URLs
|
/// Spawn URL launcher when clicking on URLs.
|
||||||
fn launch_url(&self, url: Url) {
|
fn launch_url(&self, url: Url) {
|
||||||
if self.ctx.mouse().block_url_launcher {
|
if self.ctx.mouse().block_url_launcher {
|
||||||
return;
|
return;
|
||||||
|
@ -844,7 +847,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
self.ctx.mouse_mut().last_button = button;
|
self.ctx.mouse_mut().last_button = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process key input
|
/// Process key input.
|
||||||
pub fn process_key(&mut self, input: KeyboardInput) {
|
pub fn process_key(&mut self, input: KeyboardInput) {
|
||||||
self.ctx.modifiers().update(input);
|
self.ctx.modifiers().update(input);
|
||||||
|
|
||||||
|
@ -862,17 +865,13 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
match input.state {
|
match input.state {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
*self.ctx.received_count() = 0;
|
*self.ctx.received_count() = 0;
|
||||||
*self.ctx.suppress_chars() = false;
|
self.process_key_bindings(input);
|
||||||
|
|
||||||
if self.process_key_bindings(input) {
|
|
||||||
*self.ctx.suppress_chars() = true;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ElementState::Released => *self.ctx.suppress_chars() = false,
|
ElementState::Released => *self.ctx.suppress_chars() = false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a received character
|
/// Process a received character.
|
||||||
pub fn received_char(&mut self, c: char) {
|
pub fn received_char(&mut self, c: char) {
|
||||||
if *self.ctx.suppress_chars() {
|
if *self.ctx.suppress_chars() {
|
||||||
return;
|
return;
|
||||||
|
@ -901,55 +900,41 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
*self.ctx.received_count() += 1;
|
*self.ctx.received_count() += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts 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
|
||||||
/// for its action to be executed.
|
/// for its action to be executed.
|
||||||
///
|
fn process_key_bindings(&mut self, input: KeyboardInput) {
|
||||||
/// Returns true if an action is executed.
|
let mode = *self.ctx.terminal().mode();
|
||||||
fn process_key_bindings(&mut self, input: KeyboardInput) -> bool {
|
|
||||||
let mut has_binding = false;
|
|
||||||
for binding in self.key_bindings {
|
|
||||||
let is_triggered = match binding.trigger {
|
|
||||||
Key::Scancode(_) => binding.is_triggered_by(
|
|
||||||
*self.ctx.terminal().mode(),
|
|
||||||
input.modifiers,
|
|
||||||
&Key::Scancode(input.scancode),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
_ => {
|
|
||||||
if let Some(key) = input.virtual_keycode {
|
|
||||||
let key = Key::from_glutin_input(key);
|
|
||||||
binding.is_triggered_by(
|
|
||||||
*self.ctx.terminal().mode(),
|
|
||||||
input.modifiers,
|
|
||||||
&key,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_triggered {
|
*self.ctx.suppress_chars() = self
|
||||||
// binding was triggered; run the action
|
.key_bindings
|
||||||
|
.iter()
|
||||||
|
.filter(|binding| {
|
||||||
|
let key = match (binding.trigger, input.virtual_keycode) {
|
||||||
|
(Key::Scancode(_), _) => Key::Scancode(input.scancode),
|
||||||
|
(_, Some(key)) => Key::from_glutin_input(key),
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
binding.is_triggered_by(mode, input.modifiers, &key, false)
|
||||||
|
})
|
||||||
|
.fold(None, |suppress_chars, binding| {
|
||||||
|
// Binding was triggered; run the action
|
||||||
binding.execute(&mut self.ctx, false);
|
binding.execute(&mut self.ctx, false);
|
||||||
has_binding = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
has_binding
|
// Don't suppress when there has been a `ReceiveChar` action
|
||||||
|
Some(suppress_chars.unwrap_or(true) && binding.action != Action::ReceiveChar)
|
||||||
|
})
|
||||||
|
// Don't suppress char if no bindings were triggered
|
||||||
|
.unwrap_or(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts 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
|
||||||
/// for its action to be executed.
|
/// for its action to be executed.
|
||||||
///
|
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) {
|
||||||
/// Returns true if an action is executed.
|
|
||||||
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool {
|
|
||||||
let mut has_binding = false;
|
|
||||||
for binding in self.mouse_bindings {
|
for binding in self.mouse_bindings {
|
||||||
if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &button, true) {
|
if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &button, true) {
|
||||||
// binding was triggered; run the action
|
// binding was triggered; run the action
|
||||||
|
@ -960,11 +945,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
| TermMode::MOUSE_MOTION,
|
| TermMode::MOUSE_MOTION,
|
||||||
);
|
);
|
||||||
binding.execute(&mut self.ctx, mouse_mode);
|
binding.execute(&mut self.ctx, mouse_mode);
|
||||||
has_binding = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
has_binding
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the message bar's message if there is some at the specified point
|
/// Return the message bar's message if there is some at the specified point
|
||||||
|
|
Loading…
Reference in New Issue