Skip to content

Commit a70ac2c

Browse files
committed
Add encode_raw() function to keymap
Signed-off-by: Sean Young <[email protected]>
1 parent 316666d commit a70ac2c

File tree

6 files changed

+521
-36
lines changed

6 files changed

+521
-36
lines changed

Diff for: irp/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use protocols::Protocol;
2424
use num_rational::Rational64;
2525
use std::{collections::HashMap, fmt, rc::Rc};
2626

27-
#[derive(Debug, PartialEq, Default, Eq)]
27+
#[derive(Debug, PartialEq, Default, Clone, Eq)]
2828
/// An encoded raw infrared message
2929
pub struct Message {
3030
/// The carrier for the message. None means unknown, Some(0) means unmodulated

Diff for: src/bin/commands/config.rs

-8
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,6 @@ fn load_keymap(inputdev: &Device, keymap_filename: &Path) {
183183
}
184184
};
185185

186-
let scancode = match u64::from_str_radix(scancode.trim_start_matches("0x"), 16) {
187-
Ok(scancode) => scancode,
188-
Err(_) => {
189-
eprintln!("error: ‘{scancode}’ is not a valid scancode");
190-
continue;
191-
}
192-
};
193-
194186
// Kernels from before v5.7 want the scancode in 4 bytes; try this if possible
195187
let scancode = if let Ok(scancode) = u32::try_from(scancode) {
196188
scancode.to_ne_bytes().to_vec()

Diff for: src/keymap/encode.rs

+40
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@ use super::{Keymap, LinuxProtocol};
22
use irp::{Irp, Message, Vartable};
33

44
impl Keymap {
5+
pub fn encode(&self, code: &str, repeats: u64) -> Result<Message, String> {
6+
if let Some(scancodes) = &self.scancodes {
7+
if let Some((scancode, _)) = scancodes.iter().find(|(_, v)| *v == code) {
8+
return self.encode_scancode(*scancode, repeats);
9+
}
10+
}
11+
12+
self.encode_raw(code, repeats)
13+
}
14+
515
pub fn encode_scancode(&self, scancode: u64, repeats: u64) -> Result<Message, String> {
616
let irp = if let Some(i) = &self.irp {
717
i.as_str()
@@ -42,6 +52,36 @@ impl Keymap {
4252

4353
irp.encode_raw(vars, repeats)
4454
}
55+
56+
pub fn encode_raw(&self, code: &str, repeats: u64) -> Result<Message, String> {
57+
if let Some(raw) = &self.raw {
58+
if let Some(raw) = raw.iter().find(|e| e.keycode == code) {
59+
if let Some(pronto) = &raw.pronto {
60+
return Ok(pronto.encode(repeats as usize));
61+
}
62+
63+
let e = raw.raw.as_ref().unwrap();
64+
65+
let mut m = e.clone();
66+
67+
if repeats > 0 && m.has_trailing_gap() {
68+
let rep = raw.repeat.as_ref().unwrap_or(e);
69+
70+
for _ in 0..repeats {
71+
m.extend(rep);
72+
73+
if rep.has_trailing_gap() {
74+
break;
75+
}
76+
}
77+
}
78+
79+
return Ok(m);
80+
}
81+
}
82+
83+
Err(format!("{code} not found"))
84+
}
4585
}
4686

4787
fn gen_mask(v: u32) -> u64 {

Diff for: src/keymap/mod.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
1+
use irp::{Message, Pronto};
12
use std::collections::HashMap;
23

34
mod encode;
45
mod parse;
56
mod protocol;
67

78
/// A Linux keymap, either toml or text format used by ir-keytable
8-
#[derive(PartialEq, Eq, Debug, Default)]
9+
#[derive(PartialEq, Debug, Default)]
910
pub struct Keymap {
1011
pub name: String,
1112
pub protocol: String,
1213
pub variant: Option<String>,
1314
pub irp: Option<String>,
1415
pub rc_protocol: Option<u16>,
1516
pub raw: Option<Vec<Raw>>,
16-
pub scancodes: Option<HashMap<String, String>>,
17+
pub scancodes: Option<HashMap<u64, String>>,
1718
}
1819

19-
#[derive(PartialEq, Eq, Debug)]
20+
#[derive(PartialEq, Debug)]
2021
pub struct Raw {
2122
pub keycode: String,
22-
pub raw: Option<String>,
23-
pub repeat: Option<String>,
24-
pub pronto: Option<String>,
23+
pub raw: Option<Message>,
24+
pub repeat: Option<Message>,
25+
pub pronto: Option<Pronto>,
2526
}
2627

2728
pub struct LinuxProtocol {

Diff for: src/keymap/parse.rs

+35-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Parse linux rc keymaps
22
33
use super::{Keymap, Raw};
4+
use irp::{Message, Pronto};
45
use std::{collections::HashMap, ffi::OsStr, fmt::Write, path::Path};
56
use toml::{Table, Value};
67

@@ -12,7 +13,8 @@ peg::parser! {
1213
let mut scancodes = HashMap::new();
1314

1415
for (code, name) in lines.into_iter().flatten() {
15-
scancodes.insert(code.to_owned(), name.to_owned());
16+
let code = string_to_scancode(code).unwrap();
17+
scancodes.insert(code, name.to_owned());
1618
}
1719

1820
let mut protocol = vec![Keymap {
@@ -60,6 +62,13 @@ peg::parser! {
6062
}
6163
}
6264

65+
fn string_to_scancode(s: &str) -> Result<u64, std::num::ParseIntError> {
66+
if let Some(hex) = s.strip_prefix("0x") {
67+
u64::from_str_radix(hex, 16)
68+
} else {
69+
str::parse(s)
70+
}
71+
}
6372
impl Keymap {
6473
/// Parse a rc keymap file, either toml or old text format. No validation is done of key codes or protocol names
6574
pub fn parse(contents: &str, filename: &Path) -> Result<Vec<Keymap>, String> {
@@ -127,19 +136,22 @@ fn parse_toml(contents: &str, filename: &Path) -> Result<Vec<Keymap>, String> {
127136
};
128137

129138
let raw = if let Some(Value::String(raw)) = e.get("raw") {
130-
Some(raw.to_owned())
139+
let raw = Message::parse(raw)?;
140+
Some(raw)
131141
} else {
132142
None
133143
};
134144

135145
let repeat = if let Some(Value::String(repeat)) = e.get("repeat") {
136-
Some(repeat.to_owned())
146+
let repeat = Message::parse(repeat)?;
147+
Some(repeat)
137148
} else {
138149
None
139150
};
140151

141152
let pronto = if let Some(Value::String(pronto)) = e.get("pronto") {
142-
Some(pronto.to_owned())
153+
let pronto = Pronto::parse(pronto)?;
154+
Some(pronto)
143155
} else {
144156
None
145157
};
@@ -182,12 +194,14 @@ fn parse_toml(contents: &str, filename: &Path) -> Result<Vec<Keymap>, String> {
182194
if let Some(Value::Table(codes)) = entry.get("scancodes") {
183195
let mut res = HashMap::new();
184196

185-
for (key, value) in codes {
186-
let Value::String(value) = value else {
187-
return Err(format!("{}: scancode should be string", filename.display()));
197+
for (scancode, keycode) in codes {
198+
let scancode = string_to_scancode(scancode)
199+
.map_err(|_| format!("{scancode} is a not valid scancode"))?;
200+
let Value::String(keycode) = keycode else {
201+
return Err(format!("{}: keycode should be string", filename.display()));
188202
};
189203

190-
res.insert(key.to_owned(), value.to_owned());
204+
res.insert(scancode, keycode.to_owned());
191205
}
192206

193207
scancodes = Some(res);
@@ -407,8 +421,8 @@ fn parse_toml_test() {
407421
assert_eq!(k[0].variant, Some(String::from("rc5")));
408422
if let Some(scancodes) = &k[0].scancodes {
409423
for s in scancodes {
410-
match (s.0.as_str(), s.1.as_str()) {
411-
("0x1e3b", "KEY_SELECT") | ("0x1e3d", "KEY_POWER2") | ("0x1e1c", "KEY_TV") => {}
424+
match (s.0, s.1.as_str()) {
425+
(0x1e3b, "KEY_SELECT") | (0x1e3d, "KEY_POWER2") | (0x1e1c, "KEY_TV") => {}
412426
_ => panic!("{s:?} not expected"),
413427
}
414428
}
@@ -473,8 +487,8 @@ fn parse_text_test() {
473487
assert_eq!(k[0].variant, None);
474488
if let Some(scancodes) = &k[0].scancodes {
475489
for s in scancodes {
476-
match (s.0.as_str(), s.1.as_str()) {
477-
("0x1e3b", "KEY_SELECT") | ("0x1e3d", "KEY_POWER2") | ("0x1e1c", "KEY_TV") => {}
490+
match (s.0, s.1.as_str()) {
491+
(0x1e3b, "KEY_SELECT") | (0x1e3d, "KEY_POWER2") | (0x1e1c, "KEY_TV") => {}
478492
_ => panic!("{s:?} not expected"),
479493
}
480494
}
@@ -498,11 +512,11 @@ fn parse_text_test() {
498512
assert_eq!(k[0].variant, None);
499513
if let Some(scancodes) = &k[0].scancodes {
500514
for s in scancodes {
501-
match (s.0.as_str(), s.1.as_str()) {
502-
("0x800f0400", "KEY_NUMERIC_0")
503-
| ("0x800f0401", "KEY_NUMERIC_1")
504-
| ("0x800f0402", "KEY_NUMERIC_2")
505-
| ("0x800f0403", "KEY_NUMERIC_3") => {}
515+
match (s.0, s.1.as_str()) {
516+
(0x800f0400, "KEY_NUMERIC_0")
517+
| (0x800f0401, "KEY_NUMERIC_1")
518+
| (0x800f0402, "KEY_NUMERIC_2")
519+
| (0x800f0403, "KEY_NUMERIC_3") => {}
506520
_ => panic!("{s:?} not expected"),
507521
}
508522
}
@@ -522,10 +536,10 @@ fn parse_text_test() {
522536
assert_eq!(k[0].variant, None);
523537
if let Some(scancodes) = &k[0].scancodes {
524538
for s in scancodes {
525-
match (s.0.as_str(), s.1.as_str()) {
526-
("0x28c0", "KEY_NUMERIC_0")
527-
| ("0x28c1", "KEY_NUMERIC_1")
528-
| ("0x28c2", "KEY_NUMERIC_2") => {}
539+
match (s.0, s.1.as_str()) {
540+
(0x28c0, "KEY_NUMERIC_0")
541+
| (0x28c1, "KEY_NUMERIC_1")
542+
| (0x28c2, "KEY_NUMERIC_2") => {}
529543
_ => panic!("{s:?} not expected"),
530544
}
531545
}

0 commit comments

Comments
 (0)