Thanks to visit codestin.com
Credit goes to docs.rs

Struct Keybinds

Source
pub struct Keybinds<A> { /* private fields */ }
Expand description

A dispatcher that takes key inputs and dispatches the corresponding key bindings’ actions.

The Keybinds::dispatch method dispatches an action for the given key input. The dispatcher receives key inputs as a key sequence. When the sequence matches to one of the defined key bindings, it returns the corresponding action.

When some key binding matches to a key sequence, the dispatcher dispatches the corresponding action even if some other key bindings are ongoing. For example, if “a b” and “a b c” are defined, the sequence “a” → “b” matches to the binding “a b” ignoring matching to “a b c” is ongoing hence “a b c” will never be triggered.

If the interval of key inputs exceeds the timeout (default to 1 second), the key sequence breaks there. For example, when “b” input follows “a” input after 2 seconds, each inputs “a” and “b” are treated as single key inputs, not a key sequence “a b”. Please see Keybinds::set_timeout for the code example.

use keybinds::{Keybinds, KeyInput, Key, Mods};

#[derive(PartialEq, Eq, Debug)]
enum Action {
    Foo,
    Bar,
}

let mut keybinds = Keybinds::default();

// Key sequence "f" → "o" → "o"
keybinds.bind("f o o", Action::Foo).unwrap();
// Sequence of key combinations
keybinds.bind("Ctrl+b Ctrl+a", Action::Bar).unwrap();

assert_eq!(keybinds.dispatch('f'), None);
assert_eq!(keybinds.dispatch('o'), None);
assert_eq!(keybinds.dispatch('o'), Some(&Action::Foo));

assert_eq!(keybinds.dispatch(KeyInput::new('b', Mods::CTRL)), None);
assert_eq!(keybinds.dispatch(KeyInput::new('a', Mods::CTRL)), Some(&Action::Bar));

Implementations§

Source§

impl<A> Keybinds<A>

Source

pub fn new(binds: Vec<Keybind<A>>) -> Self

Create a Keybinds instance from the array of key bindings.

If you want to collect a Keybinds instance from an iterator, Keybinds::from_iter is also useful.

use keybinds::{Keybind, Keybinds, Key, Mods, KeyInput};

enum Action {
    Foo,
    Bar,
    Piyo,
}

let binds = vec![
    Keybind::new('a', Action::Foo),
    Keybind::new(Key::Enter, Action::Bar),
    Keybind::new(KeyInput::new(Key::Up, Mods::CTRL), Action::Piyo),
];

let keybinds = Keybinds::new(binds);
assert_eq!(keybinds.as_slice().len(), 3);
Source

pub fn push(&mut self, bind: Keybind<A>)

Push a new Keybind instance. If this method is called while some key binding matching is ongoing, the matching is reset.

use keybinds::{Keybinds, Keybind};

struct Action;

let mut keybinds = Keybinds::default();

keybinds.push(Keybind::new('x', Action));
assert_eq!(keybinds.as_slice().len(), 1);
Source

pub fn bind(&mut self, key_sequence: &str, action: A) -> Result<()>

Define a new key binding. If the key sequence does not follow the syntax, this method returns an error.

use keybinds::{Keybinds, Keybind, KeyInput, Mods};

#[derive(PartialEq, Eq, Debug)]
struct Action;

let mut keybinds = Keybinds::default();

keybinds.bind("Ctrl+x Ctrl+y", Action).unwrap();
keybinds.bind("Foo+x", Action).unwrap_err(); // Unknown modifier "Foo"

assert_eq!(keybinds.as_slice().len(), 1);

// Dispatch the action
assert_eq!(keybinds.dispatch(KeyInput::new('x', Mods::CTRL)), None);          // Matching is ongoing
assert_eq!(keybinds.dispatch(KeyInput::new('y', Mods::CTRL)), Some(&Action)); // Dispatched
Examples found in repository?
examples/winit.rs (line 29)
24    fn default() -> Self {
25        // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
26        let mut keybinds = Keybinds::default();
27
28        // Key bindings to dispatch the actions
29        keybinds.bind("h i", Action::SayHi).unwrap();
30        keybinds.bind("Mod+m", Action::ToggleMaximized).unwrap();
31        keybinds.bind("Mod+Alt+t", Action::ToggleTheme).unwrap();
32        keybinds.bind("Mod+x Mod+c", Action::Exit).unwrap();
33
34        Self {
35            window: None,
36            keybinds,
37            converter: WinitEventConverter::default(),
38        }
39    }
More examples
Hide additional examples
examples/iced.rs (line 40)
35    fn default() -> Self {
36        // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
37        let mut keybinds = Keybinds::default();
38
39        // Define the key bindings
40        keybinds.bind("Mod+m", Action::ToggleMaximize).unwrap();
41        keybinds.bind("H e l l o", Action::SayHello).unwrap();
42        keybinds.bind("Mod+T", Action::ToggleTheme).unwrap();
43        keybinds.bind("Mod+x Mod+c", Action::Exit).unwrap();
44
45        Self {
46            window_id: window::Id::unique(),
47            ongoing_input: "".to_string(),
48            last_action: "".to_string(),
49            maximized: false,
50            theme: Theme::Dark,
51            help: keybinds
52                .as_slice()
53                .iter()
54                .map(|b| (format!("{}", b.seq), b.action))
55                .collect(),
56            keybinds,
57        }
58    }
examples/minimal.rs (line 16)
11fn main() -> io::Result<()> {
12    // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
13    let mut keybinds = Keybinds::default();
14
15    // Register key bindings to dispatch the actions
16    keybinds.bind("h e l l o", Action::SayHello).unwrap();
17    keybinds.bind("Esc", Action::ExitApp).unwrap();
18
19    println!("Type inputs and send it by hitting Enter key. Send Esc to exit");
20    for b in io::stdin().lock().bytes() {
21        // Convert your key input into `KeyInput` struct
22        let input = match b? {
23            b'\x1b' => KeyInput::from(Key::Esc),
24            b => KeyInput::from(b as char),
25        };
26        println!("Key input: {input:?}");
27
28        // Try to dispatch action by `dispatch` method
29        if let Some(action) = keybinds.dispatch(input) {
30            println!("Dispatched action: {action:?}");
31            match action {
32                Action::SayHello => println!("Hello!"),
33                Action::ExitApp => break,
34            }
35        }
36    }
37
38    Ok(())
39}
examples/termwiz.rs (line 24)
19fn main() -> Result<(), Error> {
20    // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
21    let mut keybinds = Keybinds::default();
22
23    // Key bindings to dispatch the actions
24    keybinds.bind("h i", Action::SayHi).unwrap();
25    keybinds.bind("Left", Action::MoveLeft).unwrap();
26    keybinds.bind("Ctrl+p", Action::Paste).unwrap();
27    keybinds.bind("Ctrl+x Ctrl+c", Action::ExitApp).unwrap();
28
29    let caps = Capabilities::new_from_env()?;
30    let terminal = new_terminal(caps)?;
31
32    let mut buf = BufferedTerminal::new(terminal)?;
33    buf.add_change("Type Ctrl+x Ctrl+c to exit");
34    buf.add_change(Change::CursorPosition {
35        x: Position::Absolute(0),
36        y: Position::Absolute(2),
37    });
38    buf.flush()?;
39    buf.terminal().set_raw_mode()?;
40
41    loop {
42        let Some(input) = buf.terminal().poll_input(None)? else {
43            continue;
44        };
45
46        // Dispatch action by directly passing `InputEvent` to `dispatch` method.
47        let action = keybinds.dispatch(&input);
48
49        buf.add_change(Change::CursorPosition {
50            x: Position::Absolute(0),
51            y: Position::Absolute(0),
52        });
53        buf.add_change(Change::ClearToEndOfLine(ColorAttribute::Default));
54        if let Some(action) = action {
55            buf.add_change(Change::Attribute(AttributeChange::Foreground(
56                AnsiColor::Red.into(),
57            )));
58            buf.add_change(format!("Action: {action:?}"));
59        }
60
61        buf.add_change(Change::CursorPosition {
62            x: Position::Absolute(0),
63            y: Position::Absolute(2),
64        });
65        buf.add_change(Change::ClearToEndOfLine(ColorAttribute::Default));
66        buf.add_change(format!("KeyInput: {:?}", KeyInput::from(input)));
67
68        buf.flush()?;
69
70        if action == Some(&Action::ExitApp) {
71            return Ok(());
72        }
73    }
74}
Source

pub fn dispatch<I: Into<KeyInput>>(&mut self, input: I) -> Option<&A>

Dispatch an action for the given key input.

This method accepts various values which implement Into<KeyInput>. For example, char value is converted into a single-character key input with no modifiers. Conversions from key event types in several frameworks are supported by enabling the optional features.

use keybinds::{Keybinds, KeyInput, Key, Mods};

#[derive(PartialEq, Eq, Debug)]
enum Action {
    Foo,
}

let mut keybinds = Keybinds::default();

keybinds.bind("f Ctrl+o Enter", Action::Foo).unwrap();

// Input "f" key with no modifiers
assert_eq!(keybinds.dispatch('f'), None);
// Input "o" key with Ctrl modifier
assert_eq!(keybinds.dispatch(KeyInput::new('o', Mods::CTRL)), None);
// Input "Enter" key with no modifiers
assert_eq!(keybinds.dispatch(Key::Enter), Some(&Action::Foo));
Examples found in repository?
examples/vim.rs (line 393)
387    fn dispatch(&mut self, input: KeyInput) -> Option<Action> {
388        let keybinds = match self.mode {
389            Mode::Normal => &mut self.normal,
390            Mode::Visual => &mut self.visual,
391            Mode::Insert => &mut self.insert,
392        };
393        keybinds.dispatch(input).copied()
394    }
More examples
Hide additional examples
examples/minimal.rs (line 29)
11fn main() -> io::Result<()> {
12    // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
13    let mut keybinds = Keybinds::default();
14
15    // Register key bindings to dispatch the actions
16    keybinds.bind("h e l l o", Action::SayHello).unwrap();
17    keybinds.bind("Esc", Action::ExitApp).unwrap();
18
19    println!("Type inputs and send it by hitting Enter key. Send Esc to exit");
20    for b in io::stdin().lock().bytes() {
21        // Convert your key input into `KeyInput` struct
22        let input = match b? {
23            b'\x1b' => KeyInput::from(Key::Esc),
24            b => KeyInput::from(b as char),
25        };
26        println!("Key input: {input:?}");
27
28        // Try to dispatch action by `dispatch` method
29        if let Some(action) = keybinds.dispatch(input) {
30            println!("Dispatched action: {action:?}");
31            match action {
32                Action::SayHello => println!("Hello!"),
33                Action::ExitApp => break,
34            }
35        }
36    }
37
38    Ok(())
39}
examples/winit.rs (line 57)
49    fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
50        // Convert the window event into key input
51        let input = self.converter.convert(&event);
52        if input.key() != Key::Ignored {
53            println!("Key input: {input:?}");
54        }
55
56        // Check if the converted key input dispatches some action
57        if let Some(action) = self.keybinds.dispatch(input) {
58            println!("Action: {action:?}");
59
60            match action {
61                Action::SayHi => println!("Hi!"),
62                Action::ToggleMaximized => {
63                    let window = self.window.as_ref().unwrap();
64                    window.set_maximized(!window.is_maximized());
65                }
66                Action::ToggleTheme => {
67                    let window = self.window.as_ref().unwrap();
68                    let theme = match window.theme() {
69                        Some(Theme::Dark) => Theme::Light,
70                        _ => Theme::Dark,
71                    };
72                    window.set_theme(Some(theme));
73                }
74                Action::Exit => event_loop.exit(),
75            }
76        }
77
78        if let WindowEvent::CloseRequested = event {
79            event_loop.exit();
80        }
81    }
examples/crossterm.rs (line 78)
64fn main() -> io::Result<()> {
65    // Parse the configuration from the file content
66    let config: Config = toml::from_str(CONFIG_FILE_CONTENT).unwrap();
67
68    // `Keybinds` instance is a key bindings dispatcher that receives key inputs and
69    // dispatches the corresponding actions.
70    let mut keybinds = config.keyboard;
71
72    enable_raw_mode()?;
73    let mut stdout = io::stdout();
74
75    // Read the crossterm's key events and pass it to `Keybinds::dispatch` directly.
76    while let Ok(event) = event::read() {
77        // If the event triggered some action, handle it using `match`
78        if let Some(action) = keybinds.dispatch(&event) {
79            match action {
80                Action::Exit => break,
81                Action::Up => execute!(stdout, cursor::MoveUp(1))?,
82                Action::Down => execute!(stdout, cursor::MoveDown(1))?,
83                Action::Left => execute!(stdout, cursor::MoveLeft(1))?,
84                Action::Right => execute!(stdout, cursor::MoveRight(1))?,
85                Action::Top => execute!(stdout, cursor::MoveUp(9999))?,
86                Action::Bottom => execute!(stdout, cursor::MoveDown(9999))?,
87                Action::Home => execute!(stdout, cursor::MoveLeft(9999))?,
88                Action::End => execute!(stdout, cursor::MoveRight(9999))?,
89            }
90        }
91    }
92
93    disable_raw_mode()
94}
examples/iced.rs (line 79)
62    fn update(&mut self, message: Message) -> Task<Message> {
63        match message {
64            Message::WindowOpen(id) => self.window_id = id,
65            Message::KeyEvent(event) => {
66                let input = KeyInput::from(&event);
67                if input.key() != Key::Ignored {
68                    println!("Key input: {input:?}");
69                    if !self.keybinds.is_ongoing() {
70                        self.last_action.clear();
71                        self.ongoing_input.clear();
72                    }
73                    if !self.ongoing_input.is_empty() {
74                        self.ongoing_input.push_str(" → ");
75                    }
76                    write!(self.ongoing_input, "{input:}").unwrap();
77                }
78
79                if let Some(action) = self.keybinds.dispatch(event) {
80                    self.last_action = format!("{action:?}");
81
82                    // Handle the dispatched action
83                    match action {
84                        Action::SayHello => println!("Hello!"),
85                        Action::ToggleMaximize => {
86                            self.maximized = !self.maximized;
87                            return window::maximize(self.window_id, self.maximized);
88                        }
89                        Action::ToggleTheme => {
90                            self.theme = match self.theme {
91                                Theme::Dark => Theme::Light,
92                                _ => Theme::Dark,
93                            };
94                        }
95                        Action::Exit => return iced::exit(),
96                    }
97                }
98            }
99            Message::Reset => {
100                self.keybinds.reset();
101                self.ongoing_input.clear();
102                self.last_action.clear();
103            }
104        }
105        Task::none()
106    }
examples/termwiz.rs (line 47)
19fn main() -> Result<(), Error> {
20    // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
21    let mut keybinds = Keybinds::default();
22
23    // Key bindings to dispatch the actions
24    keybinds.bind("h i", Action::SayHi).unwrap();
25    keybinds.bind("Left", Action::MoveLeft).unwrap();
26    keybinds.bind("Ctrl+p", Action::Paste).unwrap();
27    keybinds.bind("Ctrl+x Ctrl+c", Action::ExitApp).unwrap();
28
29    let caps = Capabilities::new_from_env()?;
30    let terminal = new_terminal(caps)?;
31
32    let mut buf = BufferedTerminal::new(terminal)?;
33    buf.add_change("Type Ctrl+x Ctrl+c to exit");
34    buf.add_change(Change::CursorPosition {
35        x: Position::Absolute(0),
36        y: Position::Absolute(2),
37    });
38    buf.flush()?;
39    buf.terminal().set_raw_mode()?;
40
41    loop {
42        let Some(input) = buf.terminal().poll_input(None)? else {
43            continue;
44        };
45
46        // Dispatch action by directly passing `InputEvent` to `dispatch` method.
47        let action = keybinds.dispatch(&input);
48
49        buf.add_change(Change::CursorPosition {
50            x: Position::Absolute(0),
51            y: Position::Absolute(0),
52        });
53        buf.add_change(Change::ClearToEndOfLine(ColorAttribute::Default));
54        if let Some(action) = action {
55            buf.add_change(Change::Attribute(AttributeChange::Foreground(
56                AnsiColor::Red.into(),
57            )));
58            buf.add_change(format!("Action: {action:?}"));
59        }
60
61        buf.add_change(Change::CursorPosition {
62            x: Position::Absolute(0),
63            y: Position::Absolute(2),
64        });
65        buf.add_change(Change::ClearToEndOfLine(ColorAttribute::Default));
66        buf.add_change(format!("KeyInput: {:?}", KeyInput::from(input)));
67
68        buf.flush()?;
69
70        if action == Some(&Action::ExitApp) {
71            return Ok(());
72        }
73    }
74}
Source

pub fn set_timeout(&mut self, timeout: Duration)

Set the timeout to wait for the next key input while matching to key bindings is ongoing. For the default timeout value, see DEFAULT_TIMEOUT.

use std::time::Duration;
use std::thread::sleep;
use keybinds::Keybinds;

struct Action;

let mut keybinds = Keybinds::default();
keybinds.bind("a b", Action).unwrap();

// Set the timeout to very small value to demonstrate the usage.
keybinds.set_timeout(Duration::from_millis(10));

// Input the first key input of key sequence "a b"
assert!(keybinds.dispatch('a').is_none());

// Make the ongoing match expire (50ms > 10ms)
sleep(Duration::from_millis(50));

// Input the second key input of key sequence "a b". However it does not dispatch the action
// because the matching expired.
assert!(keybinds.dispatch('b').is_none());
Examples found in repository?
examples/deserialize.rs (line 43)
27fn main() {
28    let configuration = r#"
29[keyboard]
30timeout = 500
31
32[keyboard.bindings]
33"Ctrl+Alt+Enter" = "OpenFile"
34"Ctrl+x Ctrl+c" = "ExitApp"
35"#;
36
37    // Parse the TOML input into the `Config` instance
38    let config: Config = toml::from_str(configuration).unwrap();
39    let mut keybinds = config.keyboard.bindings;
40
41    // Set the key sequence matching timeout if needed
42    if let Some(ms) = config.keyboard.timeout {
43        keybinds.set_timeout(Duration::from_millis(ms));
44    }
45
46    dbg!(keybinds.as_slice());
47    dbg!(keybinds.timeout());
48}
Source

pub fn reset(&mut self)

Reset the state of the dispatcher. This resets the ongoing matching state of key binding.

use keybinds::Keybinds;

struct Action;

let mut keybinds = Keybinds::default();
keybinds.bind("a b", Action).unwrap();

assert!(keybinds.dispatch('a').is_none());

// Abandon the ongoing matching for "a b"
keybinds.reset();

assert!(keybinds.dispatch('b').is_none());
Examples found in repository?
examples/iced.rs (line 100)
62    fn update(&mut self, message: Message) -> Task<Message> {
63        match message {
64            Message::WindowOpen(id) => self.window_id = id,
65            Message::KeyEvent(event) => {
66                let input = KeyInput::from(&event);
67                if input.key() != Key::Ignored {
68                    println!("Key input: {input:?}");
69                    if !self.keybinds.is_ongoing() {
70                        self.last_action.clear();
71                        self.ongoing_input.clear();
72                    }
73                    if !self.ongoing_input.is_empty() {
74                        self.ongoing_input.push_str(" → ");
75                    }
76                    write!(self.ongoing_input, "{input:}").unwrap();
77                }
78
79                if let Some(action) = self.keybinds.dispatch(event) {
80                    self.last_action = format!("{action:?}");
81
82                    // Handle the dispatched action
83                    match action {
84                        Action::SayHello => println!("Hello!"),
85                        Action::ToggleMaximize => {
86                            self.maximized = !self.maximized;
87                            return window::maximize(self.window_id, self.maximized);
88                        }
89                        Action::ToggleTheme => {
90                            self.theme = match self.theme {
91                                Theme::Dark => Theme::Light,
92                                _ => Theme::Dark,
93                            };
94                        }
95                        Action::Exit => return iced::exit(),
96                    }
97                }
98            }
99            Message::Reset => {
100                self.keybinds.reset();
101                self.ongoing_input.clear();
102                self.last_action.clear();
103            }
104        }
105        Task::none()
106    }
Source

pub fn timeout(&self) -> Duration

Get the timeout of key binding matching. See Keybinds::set_timeout to know the details of the timeout.

use std::time::Duration;
use keybinds::{Keybinds, DEFAULT_TIMEOUT};

struct Action;

let mut keybinds = Keybinds::<Action>::default();
assert_eq!(keybinds.timeout(), DEFAULT_TIMEOUT);

let duration = Duration::from_millis(500);
keybinds.set_timeout(duration);
assert_eq!(keybinds.timeout(), duration);
Examples found in repository?
examples/deserialize.rs (line 47)
27fn main() {
28    let configuration = r#"
29[keyboard]
30timeout = 500
31
32[keyboard.bindings]
33"Ctrl+Alt+Enter" = "OpenFile"
34"Ctrl+x Ctrl+c" = "ExitApp"
35"#;
36
37    // Parse the TOML input into the `Config` instance
38    let config: Config = toml::from_str(configuration).unwrap();
39    let mut keybinds = config.keyboard.bindings;
40
41    // Set the key sequence matching timeout if needed
42    if let Some(ms) = config.keyboard.timeout {
43        keybinds.set_timeout(Duration::from_millis(ms));
44    }
45
46    dbg!(keybinds.as_slice());
47    dbg!(keybinds.timeout());
48}
Source

pub fn as_slice(&self) -> &[Keybind<A>]

Get the reference to the inner slice of Keybind instances.

use keybinds::{Keybinds, Keybind};

#[derive(Clone, PartialEq, Eq, Debug)]
struct Action;

let mut keybinds = Keybinds::default();

keybinds.bind("a", Action).unwrap();

assert_eq!(keybinds.as_slice(), &[Keybind::new('a', Action)]);
Examples found in repository?
examples/deserialize.rs (line 46)
27fn main() {
28    let configuration = r#"
29[keyboard]
30timeout = 500
31
32[keyboard.bindings]
33"Ctrl+Alt+Enter" = "OpenFile"
34"Ctrl+x Ctrl+c" = "ExitApp"
35"#;
36
37    // Parse the TOML input into the `Config` instance
38    let config: Config = toml::from_str(configuration).unwrap();
39    let mut keybinds = config.keyboard.bindings;
40
41    // Set the key sequence matching timeout if needed
42    if let Some(ms) = config.keyboard.timeout {
43        keybinds.set_timeout(Duration::from_millis(ms));
44    }
45
46    dbg!(keybinds.as_slice());
47    dbg!(keybinds.timeout());
48}
More examples
Hide additional examples
examples/iced.rs (line 52)
35    fn default() -> Self {
36        // Create a key bindings dispatcher to dispatch actions for upcoming key inputs
37        let mut keybinds = Keybinds::default();
38
39        // Define the key bindings
40        keybinds.bind("Mod+m", Action::ToggleMaximize).unwrap();
41        keybinds.bind("H e l l o", Action::SayHello).unwrap();
42        keybinds.bind("Mod+T", Action::ToggleTheme).unwrap();
43        keybinds.bind("Mod+x Mod+c", Action::Exit).unwrap();
44
45        Self {
46            window_id: window::Id::unique(),
47            ongoing_input: "".to_string(),
48            last_action: "".to_string(),
49            maximized: false,
50            theme: Theme::Dark,
51            help: keybinds
52                .as_slice()
53                .iter()
54                .map(|b| (format!("{}", b.seq), b.action))
55                .collect(),
56            keybinds,
57        }
58    }
Source

pub fn is_ongoing(&self) -> bool

Return whether the matching for key bindings is ongoing.

use keybinds::Keybinds;

struct Action;

let mut keybinds = Keybinds::default();
keybinds.bind("a b", Action).unwrap();

assert!(!keybinds.is_ongoing());
keybinds.dispatch('a');
assert!(keybinds.is_ongoing());
keybinds.dispatch('b');
assert!(!keybinds.is_ongoing());
Examples found in repository?
examples/iced.rs (line 69)
62    fn update(&mut self, message: Message) -> Task<Message> {
63        match message {
64            Message::WindowOpen(id) => self.window_id = id,
65            Message::KeyEvent(event) => {
66                let input = KeyInput::from(&event);
67                if input.key() != Key::Ignored {
68                    println!("Key input: {input:?}");
69                    if !self.keybinds.is_ongoing() {
70                        self.last_action.clear();
71                        self.ongoing_input.clear();
72                    }
73                    if !self.ongoing_input.is_empty() {
74                        self.ongoing_input.push_str(" → ");
75                    }
76                    write!(self.ongoing_input, "{input:}").unwrap();
77                }
78
79                if let Some(action) = self.keybinds.dispatch(event) {
80                    self.last_action = format!("{action:?}");
81
82                    // Handle the dispatched action
83                    match action {
84                        Action::SayHello => println!("Hello!"),
85                        Action::ToggleMaximize => {
86                            self.maximized = !self.maximized;
87                            return window::maximize(self.window_id, self.maximized);
88                        }
89                        Action::ToggleTheme => {
90                            self.theme = match self.theme {
91                                Theme::Dark => Theme::Light,
92                                _ => Theme::Dark,
93                            };
94                        }
95                        Action::Exit => return iced::exit(),
96                    }
97                }
98            }
99            Message::Reset => {
100                self.keybinds.reset();
101                self.ongoing_input.clear();
102                self.last_action.clear();
103            }
104        }
105        Task::none()
106    }
Source

pub fn ongoing_inputs(&self) -> &[KeyInput]

Get the ongoing key inputs being matched to some key sequence in the key bindings.

use keybinds::{Keybinds, KeyInput};

struct Action;

let mut keybinds = Keybinds::default();
keybinds.bind("a b c", Action).unwrap();

// Initially there is no ongoing sequence.
assert_eq!(keybinds.ongoing_inputs(), &[]);

// Matching to the key sequence "a b c" is ongoing.
keybinds.dispatch('a');
keybinds.dispatch('b');
assert_eq!(keybinds.ongoing_inputs(), &['a'.into(), 'b'.into()]);

// The inputs matches to "a b c" and dispatches the action.
keybinds.dispatch('c');
assert_eq!(keybinds.ongoing_inputs(), &[]);

// This input matches nothing so there is no ongoing match.
keybinds.dispatch('d');
assert_eq!(keybinds.ongoing_inputs(), &[]);
Source

pub fn into_vec(self) -> Vec<Keybind<A>>

Convert to the inner Vec of Keybind instances. This method is useful when you need to modify the key bindings.

use keybinds::{Keybinds, Keybind};

#[derive(Clone, PartialEq, Eq, Debug)]
struct Action;

let mut keybinds = Keybinds::new(vec![Keybind::new('a', Action)]);

let mut config = keybinds.into_vec();
config[0] = Keybind::new('b', Action);

// Recreate the `Keybinds` instance
let mut keybinds = Keybinds::new(config);

assert_eq!(keybinds.dispatch('a'), None);
assert_eq!(keybinds.dispatch('b'), Some(&Action));

Trait Implementations§

Source§

impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Keybinds<A>

Available on crate feature arbitrary only.
Source§

fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self>

Generate an arbitrary value of Self from the given unstructured data. Read more
Source§

fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self, Error>

Generate an arbitrary value of Self from the entirety of the given unstructured data. Read more
Source§

fn size_hint(depth: usize) -> (usize, Option<usize>)

Get a size hint for how many bytes out of an Unstructured this type needs to construct itself. Read more
Source§

fn try_size_hint( depth: usize, ) -> Result<(usize, Option<usize>), MaxRecursionReached>

Get a size hint for how many bytes out of an Unstructured this type needs to construct itself. Read more
Source§

impl<A: Clone> Clone for Keybinds<A>

Source§

fn clone(&self) -> Keybinds<A>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A: Debug> Debug for Keybinds<A>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<A> Default for Keybinds<A>

Source§

fn default() -> Self

Create an empty Keybinds instance.

use keybinds::Keybinds;

struct Action;

let mut keybinds = Keybinds::default();
assert!(keybinds.as_slice().is_empty());

keybinds.bind("Ctrl+X", Action).unwrap();
assert!(!keybinds.as_slice().is_empty());
Source§

impl<'de, A: Deserialize<'de>> Deserialize<'de> for Keybinds<A>

Available on crate feature serde only.
Source§

fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<A> Extend<Keybind<A>> for Keybinds<A>

Source§

fn extend<I>(&mut self, iter: I)
where I: IntoIterator<Item = Keybind<A>>,

Extend the key bindings with the iterator of Keybind instances. When some key binding matching is ongoing, it will be reset.

use keybinds::{Keybinds, Keybind};

struct Action;

let mut keybinds = Keybinds::new(vec![Keybind::new(['a', 'b'], Action)]);

keybinds.dispatch('a');
assert!(keybinds.is_ongoing());

keybinds.extend([Keybind::new('c', Action), Keybind::new('d', Action)]);
assert_eq!(keybinds.as_slice().len(), 3);

// The matching state was reset
assert!(!keybinds.is_ongoing());
Source§

fn extend_one(&mut self, item: A)

🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
Source§

fn extend_reserve(&mut self, additional: usize)

🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Source§

impl<A> FromIterator<Keybind<A>> for Keybinds<A>

Source§

fn from_iter<T: IntoIterator<Item = Keybind<A>>>(iter: T) -> Self

Collect Keybinds instance from an iterator of Keybind.

use keybinds::{Keybinds, Keybind, KeySeq};

enum Action {
    Foo,
    Bar,
    Piyo,
}

let config = [
    ("f o o",         Action::Foo),
    ("Ctrl+b Ctrl+a", Action::Bar),
    ("Enter",         Action::Piyo),
];

let binds: Keybinds<_> = config
        .into_iter()
        .map(|(k, a)| k.parse().map(|k: KeySeq| Keybind::new(k, a)))
        .collect::<Result<_, _>>()
        .unwrap();

assert_eq!(binds.as_slice().len(), 3);
Source§

impl<A: PartialEq> PartialEq for Keybinds<A>

Source§

fn eq(&self, other: &Keybinds<A>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<A: Serialize> Serialize for Keybinds<A>

Available on crate feature serde only.
Source§

fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>

Serialize this value into the given Serde serializer. Read more
Source§

impl<A: Eq> Eq for Keybinds<A>

Source§

impl<A> StructuralPartialEq for Keybinds<A>

Auto Trait Implementations§

§

impl<A> Freeze for Keybinds<A>

§

impl<A> RefUnwindSafe for Keybinds<A>
where A: RefUnwindSafe,

§

impl<A> Send for Keybinds<A>
where A: Send,

§

impl<A> Sync for Keybinds<A>
where A: Sync,

§

impl<A> Unpin for Keybinds<A>
where A: Unpin,

§

impl<A> UnwindSafe for Keybinds<A>
where A: UnwindSafe,

Blanket Implementations§

Source§

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where T: Real + Zero + Arithmetics + Clone, Swp: WhitePoint<T>, Dwp: WhitePoint<T>, D: AdaptFrom<S, Swp, Dwp, T>,

Source§

fn adapt_into_using<M>(self, method: M) -> D
where M: TransformMatrix<T>,

Convert the source color to the destination color using the specified method.
Source§

fn adapt_into(self) -> D

Convert the source color to the destination color using the bradford method by default.
Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, C> ArraysFrom<C> for T
where C: IntoArrays<T>,

Source§

fn arrays_from(colors: C) -> T

Cast a collection of colors into a collection of arrays.
Source§

impl<T, C> ArraysInto<C> for T
where C: FromArrays<T>,

Source§

fn arrays_into(self) -> C

Cast this collection of arrays into a collection of colors.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for U
where T: FromCam16Unclamped<WpParam, U>,

Source§

type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T, C> ComponentsFrom<C> for T
where C: IntoComponents<T>,

Source§

fn components_from(colors: C) -> T

Cast a collection of colors into a collection of color components.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromAngle<T> for T

Source§

fn from_angle(angle: T) -> T

Performs a conversion from angle.
Source§

impl<T, U> FromStimulus<U> for T
where U: IntoStimulus<T>,

Source§

fn from_stimulus(other: U) -> T

Converts other into Self, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> IntoAngle<U> for T
where U: FromAngle<T>,

Source§

fn into_angle(self) -> U

Performs a conversion into T.
Source§

impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for U
where T: Cam16FromUnclamped<WpParam, U>,

Source§

type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T, U> IntoColor<U> for T
where U: FromColor<T>,

Source§

fn into_color(self) -> U

Convert into T with values clamped to the color defined bounds Read more
Source§

impl<T, U> IntoColorUnclamped<U> for T
where U: FromColorUnclamped<T>,

Source§

fn into_color_unclamped(self) -> U

Convert into T. The resulting color might be invalid in its color space Read more
Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoStimulus<T> for T

Source§

fn into_stimulus(self) -> T

Converts self into T, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, C> TryComponentsInto<C> for T
where C: TryFromComponents<T>,

Source§

type Error = <C as TryFromComponents<T>>::Error

The error for when try_into_colors fails to cast.
Source§

fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>

Try to cast this collection of color components into a collection of colors. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TryIntoColor<U> for T
where U: TryFromColor<T>,

Source§

fn try_into_color(self) -> Result<U, OutOfBounds<U>>

Convert into T, returning ok if the color is inside of its defined range, otherwise an OutOfBounds error is returned which contains the unclamped color. Read more
Source§

impl<C, U> UintsFrom<C> for U
where C: IntoUints<U>,

Source§

fn uints_from(colors: C) -> U

Cast a collection of colors into a collection of unsigned integers.
Source§

impl<C, U> UintsInto<C> for U
where C: FromUints<U>,

Source§

fn uints_into(self) -> C

Cast this collection of unsigned integers into a collection of colors.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> MaybeSync for T
where T: Sync,

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,