Skip to content

Commit 932863f

Browse files
committed
Release v0.1.0
0 parents  commit 932863f

File tree

13 files changed

+787
-0
lines changed

13 files changed

+787
-0
lines changed

.github/workflows/ci.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Rust
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
- name: Build
19+
run: cargo build --verbose
20+
- name: Run tests
21+
run: cargo test --verbose

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/target
2+
Cargo.lock
3+
.DS_Store
4+
5+
# Devenv
6+
.devenv*
7+
devenv.local.nix

Cargo.toml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "keymap"
3+
description = "A library for defining and parsing input events from configuration"
4+
authors = ["Marut Khumtong <[email protected]>"]
5+
version = "0.1.0"
6+
homepage = "https://github.com/rezigned/keymap-rs"
7+
repository = "https://github.com/rezigned/keymap-rs"
8+
edition = "2021"
9+
keywords = ["terminal", "event", "config", "keymapping", "keybinding"]
10+
license = "MIT"
11+
12+
[dependencies]
13+
crossterm = { version = "0.26", optional = true }
14+
termion = { version = "2.0", optional = true }
15+
pom = "3.3.0"
16+
serde = { version = "1.0", features = ["derive"] }
17+
strum = "0.25"
18+
strum_macros = "0.25"
19+
20+
[features]
21+
default = ["crossterm"]
22+
23+
[dev-dependencies]
24+
toml = "0.7"
25+
26+
[[example]]
27+
name = "crossterm"
28+
required-features = ["crossterm"]
29+
30+
[[example]]
31+
name = "termion"
32+
required-features = ["termion"]

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Marut Khumtong
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# keymap-rs
2+
3+
[![crates.io](https://img.shields.io/crates/v/keymap.svg)](https://crates.io/crates/keymap)
4+
[![Rust](https://github.com/rezigned/keymap-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/rezigned/keymap-rs/actions/workflows/ci.yml)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
6+
7+
`keymap-rs` is a library for defining input events from configurations and mapping them to the terminal library's event. (such as [crossterm](https://github.com/crossterm-rs/crossterm) or [termion](https://gitlab.redox-os.org/redox-os/termion))
8+
9+
## Getting started
10+
11+
_Please check the [examples](examples/) directory for complete examples._
12+
13+
<details>
14+
<summary>
15+
Click to show <code>Cargo.toml</code>.
16+
</summary>
17+
18+
```toml
19+
[dependencies]
20+
keymap = "0.1"
21+
```
22+
</details>
23+
24+
Let's started by defining a simple structure for mapping input key to `String`.
25+
26+
```rs
27+
use keymap::{KeyMap, Key};
28+
use serde::Deserialize;
29+
30+
#[derive(Deserialize)]
31+
struct Config(pub HashMap<KeyMap, String>)
32+
33+
let config = r#"
34+
up = "Up"
35+
down = "Down"
36+
g = "Top"
37+
G = "Bottom" # This is the same as `shift-g`
38+
esc = "Quit"
39+
"
40+
```
41+
42+
Then in your terminal library of choice (we'll be using [crossterm](https://github.com/crossterm-rs/crossterm) as an example). You can use any deserializer (e.g. `toml`, `json`, etc.) to deserialize a key from the configuration above into the terminal library's event (e.g. `crossterm::event::KeyEvent`).
43+
44+
```rs
45+
let mapping: Config = toml::from_str(config).unwrap();
46+
47+
// Read input event
48+
match read()? {
49+
Event::Key(key) => {
50+
// `Key::from` will convert `crossterm::event::KeyEvent` to `keymap::Key`
51+
if let Some(action) = config.0.get(&Key::from(key)) {
52+
match action {
53+
"Up" => println!("Move up!"),
54+
"Down" => println!("Move down!"),
55+
// ...
56+
"Quit" => break,
57+
}
58+
}
59+
}
60+
}
61+
```

examples/config.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use std::collections::HashMap;
2+
3+
use keymap::KeyMap;
4+
use serde::Deserialize;
5+
use strum_macros::Display;
6+
7+
#[derive(Debug, Deserialize, PartialEq, Display)]
8+
pub(crate) enum Action {
9+
Bottom,
10+
Down,
11+
Explode,
12+
Jump,
13+
Top,
14+
Up,
15+
Quit,
16+
}
17+
18+
#[allow(unused)]
19+
#[derive(Debug, Deserialize)]
20+
pub(crate) struct Config(pub HashMap<KeyMap, Action>);
21+
22+
#[allow(unused)]
23+
pub(crate) const CONFIG_DATA: &str = r#"
24+
up = "Up"
25+
down = "Down"
26+
ctrl-z = "Explode"
27+
shift-g = "Bottom"
28+
g = "Top"
29+
q = "Quit"
30+
esc = "Quit"
31+
space = "Jump"
32+
"#;
33+
34+
#[allow(unused)]
35+
fn main() {}

examples/crossterm.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use std::io::{self, Stdout};
2+
mod config;
3+
4+
use config::{Action, Config, CONFIG_DATA};
5+
use crossterm::{
6+
cursor,
7+
event::{read, Event},
8+
execute,
9+
style::Print,
10+
terminal::{disable_raw_mode, enable_raw_mode},
11+
};
12+
use keymap::Key;
13+
14+
fn main() -> io::Result<()> {
15+
let mut stdout = io::stdout();
16+
enable_raw_mode()?;
17+
18+
read_event(&mut stdout)?;
19+
20+
disable_raw_mode()
21+
}
22+
23+
fn read_event(stdout: &mut Stdout) -> io::Result<()> {
24+
let config: Config = toml::from_str(CONFIG_DATA).unwrap();
25+
26+
loop {
27+
let event = read()?;
28+
29+
match event {
30+
Event::Key(key) => {
31+
if let Some((k, action)) = config.0.get_key_value(&Key::from(key)) {
32+
if *action == Action::Quit {
33+
break;
34+
}
35+
36+
execute!(
37+
stdout,
38+
Print(format!("key:{} - {}\n", k, action)),
39+
cursor::MoveToNextLine(1),
40+
)?;
41+
}
42+
}
43+
_ => (),
44+
}
45+
}
46+
47+
Ok(())
48+
}

examples/termion.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
mod config;
2+
3+
use config::{CONFIG_DATA, Config, Action};
4+
use keymap::Key;
5+
use termion::event::Event;
6+
use termion::input::{TermRead, MouseTerminal};
7+
use termion::raw::IntoRawMode;
8+
use std::io::{Write, stdout, stdin};
9+
10+
fn main() {
11+
let stdin = stdin();
12+
let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
13+
14+
stdout.flush().unwrap();
15+
16+
// Parse key event
17+
let bindings: Config = toml::from_str(CONFIG_DATA).unwrap();
18+
19+
for c in stdin.events() {
20+
let evt = c.unwrap();
21+
22+
if let Event::Key(key) = evt {
23+
if let Some((k, action)) = bindings.keys.get_key_value(&Key::from(key)) {
24+
if *action == Action::Quit {
25+
break;
26+
}
27+
28+
write!(stdout, "{}{}key:{k} - {}", termion::clear::All, termion::cursor::Goto(1, 1), action).unwrap();
29+
}
30+
}
31+
32+
stdout.flush().unwrap();
33+
}
34+
}

0 commit comments

Comments
 (0)