fix(key_input): Handle shifted characters correctly
This commit fixes multiple bugs introduced in the new keymapping system: When we can't find a keymapping for a string, we simply pass it along, by calling the 'send_input_unprocessed' function with the inputted key turned into it's string representation. Turning a shifted key into it's repr. returned a doubly shifted string: 'A' turned into '<S-A>', which then fails to parse as a valid key input. Thus, we simply unshifted the value. The next bug, becoming apparent now, is caused by this: We never reshifted the value, when we converted it into a crossterm key input event.
This commit is contained in:
parent
66bf5e3b6f
commit
b54f8e59e8
|
@ -12,6 +12,7 @@ use crate::app::{
|
||||||
|
|
||||||
pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<EventStatus> {
|
pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<EventStatus> {
|
||||||
async fn default(converted_key: Key, app: &mut App<'_>, old_state: &State) -> Result<()> {
|
async fn default(converted_key: Key, app: &mut App<'_>, old_state: &State) -> Result<()> {
|
||||||
|
info!("No keymaps exist for key ('{}'), passing it along..", converted_key);
|
||||||
// Just let the input event slip through if no keymap matches
|
// Just let the input event slip through if no keymap matches
|
||||||
app.tx
|
app.tx
|
||||||
.send(Event::CommandEvent(
|
.send(Event::CommandEvent(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::{str::FromStr, fmt::Display};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use anyhow::{bail, Context};
|
use anyhow::{bail, Context};
|
||||||
use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
|
use cli_log::{debug, info};
|
||||||
|
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
|
||||||
|
|
||||||
use super::{Chars, KeyValue, Keys};
|
use super::{Chars, KeyValue, Keys};
|
||||||
|
|
||||||
|
@ -236,7 +237,33 @@ impl Into<Event> for Key {
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = Event::Key(KeyEvent {
|
let output = Event::Key(KeyEvent {
|
||||||
code: self.value.unwrap_or(KeyValue::Null).into(),
|
code: {
|
||||||
|
// We sorta hit a edge case here, if we have a shifted char we need to tell
|
||||||
|
// crossterm about that. Thus we need to manually apply the shift modifier on the
|
||||||
|
// value.
|
||||||
|
if self.shift {
|
||||||
|
if let Some(KeyValue::Char(char)) = self.value {
|
||||||
|
let upper_case_char: char = {
|
||||||
|
let chars = char.to_uppercase().collect::<Vec<char>>();
|
||||||
|
if chars.len() != 1 {
|
||||||
|
unimplemented!(
|
||||||
|
"
|
||||||
|
I have no idea how we handle this case,
|
||||||
|
we'll just have to hope, that it never comes up.
|
||||||
|
"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*chars.first().expect("We checked the length")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
KeyCode::Char(upper_case_char)
|
||||||
|
} else {
|
||||||
|
self.value.unwrap_or(KeyValue::Null).into()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.value.unwrap_or(KeyValue::Null).into()
|
||||||
|
}
|
||||||
|
},
|
||||||
modifiers,
|
modifiers,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: KeyEventState::NONE,
|
state: KeyEventState::NONE,
|
||||||
|
@ -266,8 +293,41 @@ impl TryFrom<&Event> for Key {
|
||||||
|
|
||||||
{
|
{
|
||||||
let key_code = key_event.code;
|
let key_code = key_event.code;
|
||||||
|
if output_key.shift {
|
||||||
|
// We need to deal have an edge case for shift, as the value will be in the
|
||||||
|
// shifted form (for example 'A'). If we left that, we would get "<S-A>" as
|
||||||
|
// Key representation, which can't be parsed. So we simply unshift the 'A'
|
||||||
|
// here, turning the representation into: "<S-a>"
|
||||||
|
if let KeyCode::Char(char) = key_code {
|
||||||
|
let lower_case_char: char = {
|
||||||
|
let chars = char.to_lowercase().collect::<Vec<char>>();
|
||||||
|
if chars.len() != 1 {
|
||||||
|
unimplemented!(
|
||||||
|
"
|
||||||
|
I have no idea how we handle this case,
|
||||||
|
we'll just have to hope, that it never comes up.
|
||||||
|
"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*chars.first().expect("We checked the length")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Had to translate key ('{}') to it's lowercase variant ('{}')",
|
||||||
|
char, lower_case_char
|
||||||
|
);
|
||||||
|
output_key.value = Some(KeyValue::Char(lower_case_char));
|
||||||
|
} else {
|
||||||
|
debug!(
|
||||||
|
"Key ('{}') is shifted but not a character!",
|
||||||
|
Into::<KeyValue>::into(key_code)
|
||||||
|
);
|
||||||
output_key.value = Some(key_code.into());
|
output_key.value = Some(key_code.into());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
output_key.value = Some(key_code.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(output_key)
|
Ok(output_key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,21 @@ mod test {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shift_a() {
|
||||||
|
let keys: Keys = "<S-a>".parse().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
keys,
|
||||||
|
Keys(vec![Key {
|
||||||
|
alt: false,
|
||||||
|
ctrl: false,
|
||||||
|
meta: false,
|
||||||
|
shift: true,
|
||||||
|
value: Some(KeyValue::Char('a'))
|
||||||
|
}])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_string_repr() {
|
fn test_string_repr() {
|
||||||
let key = Key {
|
let key = Key {
|
||||||
|
|
Reference in New Issue