Skip to content

Commit 1972222

Browse files
committed
fix: keybindings not trigerring correctly
1 parent d00223d commit 1972222

File tree

3 files changed

+102
-12
lines changed

3 files changed

+102
-12
lines changed

src/app.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use iced::widget::{self, Column, Space, Stack, canvas, column, container, row};
1717
use iced::{Background, Color, Element, Font, Length, Point, Rectangle, Size, Task};
1818

1919
use crate::background_image::BackgroundImage;
20-
use crate::corners::{Side, SideOrCorner};
20+
use crate::corners::{Corner, RectPlace, Side, SideOrCorner};
2121
use crate::rectangle::RectangleExt;
2222
use crate::selection::{Selection, SelectionStatus};
2323

@@ -339,6 +339,41 @@ impl App {
339339
self.error("Nothing is selected.");
340340
return Task::none();
341341
};
342+
let (image_width, image_height, _) = self.screenshot.raw();
343+
let image_height = image_height as f32;
344+
let image_width = image_width as f32;
345+
346+
*selection = match rect_place {
347+
RectPlace::SideOrCorner(SideOrCorner::Side(side)) => match side {
348+
Side::Top => selection
349+
.with_x(|_| image_width / 2.0 - selection.rect.width / 2.0)
350+
.with_y(|_| 0.0),
351+
Side::Right => selection
352+
.with_x(|_| image_width - selection.rect.width)
353+
.with_y(|_| image_height / 2.0 - selection.rect.height / 2.0),
354+
Side::Bottom => selection
355+
.with_x(|_| image_width / 2.0 - selection.rect.width / 2.0)
356+
.with_y(|_| image_height - selection.rect.height),
357+
Side::Left => selection
358+
.with_x(|_| 0.0)
359+
.with_y(|_| image_height / 2.0 - selection.rect.height / 2.0),
360+
},
361+
RectPlace::SideOrCorner(SideOrCorner::Corner(corner)) => match corner {
362+
Corner::TopLeft => selection.with_x(|_| 0.0).with_y(|_| 0.0),
363+
Corner::TopRight => selection
364+
.with_x(|_| image_width - selection.rect.width)
365+
.with_y(|_| 0.0),
366+
Corner::BottomLeft => selection
367+
.with_x(|_| 0.0)
368+
.with_y(|_| image_height - selection.rect.height),
369+
Corner::BottomRight => selection
370+
.with_x(|_| image_width - selection.rect.width)
371+
.with_y(|_| image_height - selection.rect.height),
372+
},
373+
RectPlace::Center => selection
374+
.with_x(|_| image_width / 2.0 - selection.rect.width / 2.0)
375+
.with_y(|_| image_height / 2.0 - selection.rect.height / 2.0),
376+
};
342377
}
343378
KeyAction::Move(direction, amount) => {
344379
let Some(selection) = self.selection.as_mut() else {

src/canvas.rs

+50-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! The canvas handles drawing the selection frame
22
use iced::Event::{Keyboard, Mouse};
3+
use iced::advanced::debug::core::SmolStr;
34
use iced::keyboard::Event::KeyPressed;
45
use iced::keyboard::Event::KeyReleased;
56
use iced::keyboard::Key::{self, Character, Named};
7+
use iced::keyboard::Modifiers;
68
use iced::keyboard::Modifiers as Mods;
79
use iced::keyboard::key::Named::F11;
810
use iced::keyboard::key::Named::{Enter, Escape, Shift};
@@ -108,12 +110,52 @@ impl canvas::Program<Message> for App {
108110
_bounds: Rectangle,
109111
cursor: iced::advanced::mouse::Cursor,
110112
) -> Option<widget::Action<Message>> {
111-
if let Keyboard(KeyPressed { key, modifiers, .. }) = event {
113+
if let Keyboard(KeyPressed {
114+
modifiers,
115+
text,
116+
key,
117+
..
118+
}) = event
119+
{
120+
let mut modifiers = *modifiers;
121+
122+
// Shift key does not matter. For example:
123+
// - pressing `<` and the `SHIFT` modifier will be pressed
124+
// - `G` will also trigger the `SHIFT` modifier
125+
modifiers.remove(Modifiers::SHIFT);
126+
127+
let key = if let Key::Named(name) = key {
128+
// named key takes priority over anything.
129+
//
130+
// For example, if we input `Escape` it will send the `text`
131+
// `\u{1b}` which won't match any of the keys that we have. So we must
132+
// intercept before that happens
133+
Key::Named(*name)
134+
} else {
135+
// if we input `G` for example, it actually sends:
136+
// - modifier: `shift`
137+
// - key: `g`
138+
// - text: `G`
139+
//
140+
// if we input `<` it sends:
141+
// - modifier: `shift`
142+
// - key: `,`
143+
// - text: `<`
144+
//
145+
// So `text` is our source of truth. However, sometimes it is not available.
146+
// If `key != Key::Named` and `text == None` then we use the actual `key`
147+
// as a fallback.
148+
//
149+
// It is unknown when this fallback might be used, but it is kept just in case.
150+
text.as_ref()
151+
.map_or_else(|| key.clone(), |ch| Key::Character(ch.clone()))
152+
};
112153
if let Some((_, action)) = CONFIG
113154
.keys
114155
.keys
115156
// e.g. for instance keybind for `g` should take priority over `gg`
116157
.get(&KeySequence((key.clone(), None)))
158+
.filter(|(mods, _)| modifiers == mods.0)
117159
// e.g. in this case we try the `gg` keybinding since `g` does not exist
118160
.or_else(|| {
119161
state
@@ -126,7 +168,7 @@ impl canvas::Program<Message> for App {
126168
.get(&KeySequence((last_key_pressed.clone(), Some(key.clone()))))
127169
})
128170
})
129-
.filter(|(mods, _)| *modifiers == mods.0)
171+
.filter(|(mods, _)| modifiers == mods.0)
130172
{
131173
// the last key pressed needs to be reset for it to be
132174
// correct in future invocations
@@ -140,7 +182,12 @@ impl canvas::Program<Message> for App {
140182
return Some(Action::publish(Message::KeyBind(action.clone())));
141183
}
142184

143-
state.last_key_pressed = Some(key.clone());
185+
// the "Shift" is already included in the modifiers
186+
//
187+
// This way pressing e.g. `G` would only set the last_key_pressed once
188+
if key != Named(Shift) {
189+
state.last_key_pressed = Some(key);
190+
}
144191
}
145192

146193
let message = match event {

src/config/key.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,17 @@ impl FromStr for KeyMods {
6767
return Ok(Self(Modifiers::empty()));
6868
}
6969
for modifier_str in s.split('+') {
70-
let modifier = match modifier_str {
71-
"shift" => Modifiers::SHIFT,
72-
"ctrl" => Modifiers::CTRL,
73-
"alt" => Modifiers::ALT,
74-
"super" | "windows" | "command" => Modifiers::LOGO,
75-
invalid => return Err(format!("Invalid modifier: {invalid}")),
76-
};
70+
let modifier =
71+
match modifier_str {
72+
"ctrl" => Modifiers::CTRL,
73+
"alt" => Modifiers::ALT,
74+
"super" | "windows" | "command" => Modifiers::LOGO,
75+
"shift" => return Err(
76+
"The `shift` is not supported. Use `G` instead of `g + shift` for example (or `<` instead of `, + shift`)"
77+
.to_owned(),
78+
),
79+
invalid => return Err(format!("Invalid modifier: {invalid}")),
80+
};
7781
if mods.contains(modifier) {
7882
return Err(format!("Duplicate modifier: {modifier_str}"));
7983
}
@@ -144,7 +148,11 @@ impl std::str::FromStr for KeySequence {
144148
named_key_buf.push(ch);
145149
}
146150
} else {
147-
keys.push(IcedKey::Character(SmolStr::new(ch.to_string())));
151+
if ch.is_ascii_uppercase() {
152+
keys.push(IcedKey::Character(SmolStr::new(ch.to_string())));
153+
} else {
154+
keys.push(IcedKey::Character(SmolStr::new(ch.to_string())));
155+
}
148156
}
149157
}
150158
let mut keys = keys.into_iter();

0 commit comments

Comments
 (0)