1use core::fmt;
54use nom::{
55 branch::alt,
56 bytes::complete::{tag, take_while1},
57 character::complete::{char, hex_digit1, line_ending, multispace1, not_line_ending, space0},
58 combinator::{map, opt, recognize},
59 error::{context, ErrorKind, ParseError},
60 multi::{many0, many1},
61 sequence::preceded,
62 AsChar, InputTakeAtPosition,
63};
64
65#[derive(Debug, Clone, PartialEq)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72pub enum KeyID {
73 Or(Vec<KeyID>),
75 And(Vec<KeyID>),
77 One(String),
79 Alias(String),
81}
82
83impl fmt::Display for KeyID {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 KeyID::Or(keys) => {
87 let keys_str: Vec<String> = keys.iter().map(|key| key.to_string()).collect();
88 write!(f, "{}", keys_str.join("+"))
89 }
90 KeyID::And(keys) => {
91 let keys_str: Vec<String> = keys.iter().map(|key| key.to_string()).collect();
92 write!(f, "{}", keys_str.join(","))
93 }
94 KeyID::One(key) => write!(f, "{}", key),
95 KeyID::Alias(alias) => write!(f, "!0,{}", alias),
96 }
97 }
98}
99
100#[derive(Debug, Clone, PartialEq)]
104#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
105pub struct EventLine {
106 pub event_name: String,
107 pub keyboard_id: KeyID,
108 pub mouse_id: KeyID,
109 pub gamepad_id: KeyID,
110 pub remap_key: bool,
111 pub remap_mouse: bool,
112 pub remap_gamepad: bool,
113 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
114 pub event_binary_flag: Option<String>,
115}
116
117impl fmt::Display for EventLine {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(
120 f,
121 "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
122 self.event_name,
123 self.keyboard_id,
124 self.mouse_id,
125 self.gamepad_id,
126 self.remap_key as u8,
127 self.remap_mouse as u8,
128 self.remap_gamepad as u8,
129 self.event_binary_flag.as_deref().unwrap_or_default()
130 )
131 }
132}
133
134#[derive(Debug, Clone, PartialEq)]
136#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137pub enum Line {
138 Comment(String),
140 EventLine(EventLine),
142 BlankLine,
144}
145
146impl fmt::Display for Line {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 match self {
149 Line::Comment(comment) => writeln!(f, "// {}", comment.trim()),
150 Line::EventLine(event_line) => writeln!(f, "{}", event_line),
151 Line::BlankLine => writeln!(f),
152 }
153 }
154}
155
156fn tab_space1<T, E: ParseError<T>>(input: T) -> nom::IResult<T, T, E>
158where
159 T: InputTakeAtPosition,
160 <T as InputTakeAtPosition>::Item: AsChar + Clone,
161{
162 input.split_at_position1_complete(|item| item.as_char() != '\t', ErrorKind::Space)
163}
164
165type IResult<I, O> = nom::IResult<I, O, nom::error::VerboseError<I>>;
166
167fn parse_hex(input: &str) -> IResult<&str, &str> {
168 let (input, _) = space0(input)?;
169 recognize(preceded(tag("0x"), hex_digit1))(input)
170}
171
172fn parse_flag(input: &str) -> IResult<&str, bool> {
173 let (input, flag) = alt((char('0'), char('1')))(input)?;
174 let flag = match flag {
175 '0' => false,
176 '1' => true,
177 _ => unreachable!(),
178 };
179 Ok((input, flag))
180}
181
182fn parse_key_and(input: &str) -> IResult<&str, KeyID> {
183 let (input, key) = parse_key_one(input)?;
184 let (input, ref mut keys) = many1(preceded(tag("+"), parse_key_one))(input)?;
185 let mut res = vec![key];
186 res.append(keys);
187 Ok((input, KeyID::And(res)))
188}
189
190fn parse_key_or(input: &str) -> IResult<&str, KeyID> {
191 let mut parse_and1 = alt((parse_key_and, parse_key_one));
192
193 let (input, key) = parse_and1(input)?;
194 let (input, ref mut keys) = many1(preceded(tag(","), parse_and1))(input)?;
195 let mut res = vec![key];
196 res.append(keys);
197 Ok((input, KeyID::Or(res)))
198}
199
200fn parse_key_one(input: &str) -> IResult<&str, KeyID> {
201 map(parse_hex, |key| KeyID::One(key.into()))(input)
202}
203
204fn parse_key_alias(input: &str) -> IResult<&str, KeyID> {
205 map(preceded(tag("!0,"), parse_event_name), |key| {
206 KeyID::Alias(key.into())
207 })(input)
208}
209
210fn parse_key_id(input: &str) -> IResult<&str, KeyID> {
211 alt((parse_key_alias, parse_key_or, parse_key_and, parse_key_one))(input)
212}
213
214fn parse_event_name(input: &str) -> IResult<&str, &str> {
215 context(
216 "Expected ident. non tab any string",
217 take_while1(|c: char| c != '\t'),
218 )(input)
219}
220
221fn parse_comment_line(input: &str) -> IResult<&str, Line> {
222 let (input, comment) = preceded(tag("//"), not_line_ending)(input)?;
223 let (input, _) = opt(line_ending)(input)?;
224 Ok((input, Line::Comment(comment.into())))
225}
226
227fn parse_event_line(input: &str) -> IResult<&str, Line> {
228 let (input, event_name) = parse_event_name(input)?;
229 let (input, _) = tab_space1(input)?;
230 let (input, keyboard_id) = parse_key_id(input)?;
231 let (input, _) = tab_space1(input)?;
232 let (input, mouse_id) = parse_key_id(input)?;
233 let (input, _) = tab_space1(input)?;
234 let (input, gamepad_id) = parse_key_id(input)?;
235 let (input, _) = tab_space1(input)?;
236 let (input, remap_key) = parse_flag(input)?;
237 let (input, _) = tab_space1(input)?;
238 let (input, remap_mouse) = parse_flag(input)?;
239 let (input, _) = tab_space1(input)?;
240 let (input, remap_gamepad) = parse_flag(input)?;
241 let (input, event_binary_flag) = opt(preceded(tab_space1, parse_hex))(input)?;
242 let (input, _) = space0(input)?; let (input, _) = preceded(opt(tag("\r")), opt(tag("\n")))(input)?;
244
245 Ok((
246 input,
247 Line::EventLine(EventLine {
248 event_name: event_name.into(),
249 keyboard_id,
250 mouse_id,
251 gamepad_id,
252 remap_key,
253 remap_mouse,
254 remap_gamepad,
255 event_binary_flag: event_binary_flag.map(|event| event.into()),
256 }),
257 ))
258}
259
260fn parse_blank_line(input: &str) -> IResult<&str, Line> {
261 let (input, _) = multispace1(input)?;
262 Ok((input, Line::BlankLine))
263}
264
265pub fn control_map_parser(input: &str) -> IResult<&str, Vec<Line>> {
322 let parse_line = alt((parse_blank_line, parse_comment_line, parse_event_line));
323 many0(parse_line)(input)
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329 use pretty_assertions::assert_eq;
330
331 #[test]
332 fn test_parse_hex() {
333 let input = "0x1234";
334 let expected_output = Ok(("", "0x1234"));
335 let result = parse_hex(input);
336 assert_eq!(result, expected_output);
337 }
338
339 #[test]
340 fn test_parse_flag() {
341 let input = "0";
342 let expected_output = Ok(("", false));
343 let result = parse_flag(input);
344 assert_eq!(result, expected_output);
345 }
346
347 #[test]
348 fn test_parse_key_id_one() {
349 let input = "0x1234";
350 let expected_output = Ok(("", KeyID::One("0x1234".into())));
351 let result = parse_key_id(input);
352 assert_eq!(result, expected_output);
353 }
354
355 #[test]
356 fn test_parse_key_id_and() {
357 let input = "0x1234+0x5678+0x9abc";
358 let expected_output = Ok((
359 "",
360 KeyID::And(vec![
361 KeyID::One("0x1234".into()),
362 KeyID::One("0x5678".into()),
363 KeyID::One("0x9abc".into()),
364 ]),
365 ));
366 let result = parse_key_id(input);
367 assert_eq!(result, expected_output);
368 }
369
370 #[test]
371 fn test_parse_key_id_or() {
372 let input = "0x2a+0x0f,0x36+0x0,0x1234,0x5678,0x9abc";
373 let expected_output = Ok((
374 "",
375 KeyID::Or(vec![
376 KeyID::And(vec![KeyID::One("0x2a".into()), KeyID::One("0x0f".into())]),
377 KeyID::And(vec![KeyID::One("0x36".into()), KeyID::One("0x0".into())]),
378 KeyID::One("0x1234".into()),
379 KeyID::One("0x5678".into()),
380 KeyID::One("0x9abc".into()),
381 ]),
382 ));
383 let result = parse_key_id(input);
384 assert_eq!(result, expected_output)
385 }
386
387 #[test]
388 fn test_parse_comment_line() {
389 let input = "// This is a comment\n";
390 let expected_output = Ok(("", Line::Comment(" This is a comment".into())));
391 let result = parse_comment_line(input);
392 assert_eq!(result, expected_output);
393 }
394}