1use std::{cmp::Ordering, str::FromStr};
4
5use serde::{Deserialize, Serialize};
6use serde_with::{DisplayFromStr, serde_as};
7
8use crate::{
9 Anchor, DofError, DofErrorInner as DE, Fingering, FormFactor, Keyboard, NamedFingering, Result,
10 keyboard_conv,
11};
12
13#[derive(Clone, Debug, PartialEq)]
16pub struct PhysicalKey {
17 x: f64,
18 y: f64,
19 width: f64,
20 height: f64,
21}
22
23impl PhysicalKey {
24 pub const fn x(&self) -> f64 {
26 self.x
27 }
28
29 pub const fn y(&self) -> f64 {
31 self.y
32 }
33
34 pub const fn width(&self) -> f64 {
36 self.width
37 }
38
39 pub const fn height(&self) -> f64 {
41 self.height
42 }
43
44 pub const fn xy(x: f64, y: f64) -> Self {
46 Self {
47 x,
48 y,
49 width: 1.0,
50 height: 1.0,
51 }
52 }
53
54 pub const fn xyw(x: f64, y: f64, width: f64) -> Self {
56 Self {
57 x,
58 y,
59 width,
60 height: 1.0,
61 }
62 }
63
64 pub const fn xywh(x: f64, y: f64, width: f64, height: f64) -> Self {
66 Self {
67 x,
68 y,
69 width,
70 height,
71 }
72 }
73
74 pub(crate) fn normalized(self) -> Self {
76 let (x, width) = match self.width < 0.0 {
77 true => (self.x + self.width, self.width.abs()),
78 false => (self.x, self.width),
79 };
80
81 let (y, height) = match self.height < 0.0 {
82 true => (self.y + self.height, self.height.abs()),
83 false => (self.y, self.height),
84 };
85
86 Self {
87 x,
88 y,
89 width,
90 height,
91 }
92 }
93}
94
95impl std::fmt::Display for PhysicalKey {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 let omit = |v: f64| v >= 0.999999 || v <= 1.000001;
98
99 match (omit(self.width), omit(self.height)) {
100 (true, true) => write!(f, "{} {}", self.x, self.y),
101 (false, true) => write!(f, "{} {} {}", self.x, self.y, self.width),
102 (_, false) => write!(f, "{} {} {} {}", self.x, self.y, self.width, self.height),
103 }
104 }
105}
106
107impl FromStr for PhysicalKey {
108 type Err = DofError;
109
110 fn from_str(s: &str) -> Result<Self> {
111 let trimmed = s.trim();
112
113 if trimmed.is_empty() {
114 return Err(DE::EmptyPhysKey.into());
115 }
116
117 let vals = trimmed
118 .split_whitespace()
119 .map(|s| s.parse::<f64>())
120 .collect::<std::result::Result<Vec<_>, _>>()
121 .map_err(|_| DE::KeyParseError(trimmed.into()))?;
122
123 match vals.as_slice() {
124 &[x, y] => Ok(Self::xy(x, y)),
125 &[x, y, width] => Ok(Self::xyw(x, y, width)),
126 &[x, y, width, height] => Ok(Self::xywh(x, y, width, height)),
127 sl => Err(DE::ValueAmountError(sl.len(), trimmed.into()).into()),
128 }
129 }
130}
131
132#[serde_as]
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
135pub struct PhysicalKeyboard(#[serde_as(as = "Vec<Vec<DisplayFromStr>>")] Vec<Vec<PhysicalKey>>);
136
137impl Keyboard for PhysicalKeyboard {
138 type K = PhysicalKey;
139
140 fn inner(&self) -> &[Vec<Self::K>] {
141 &self.0
142 }
143
144 fn into_inner(self) -> Vec<Vec<Self::K>> {
145 self.0
146 }
147}
148
149impl From<Vec<Vec<PhysicalKey>>> for PhysicalKeyboard {
150 fn from(v: Vec<Vec<PhysicalKey>>) -> Self {
151 Self(v)
152 }
153}
154
155#[derive(Clone, Debug, PartialEq)]
158pub struct RelativeKey {
159 pub(crate) width: f64,
160 pub(crate) has_key: bool,
161}
162
163impl std::fmt::Display for RelativeKey {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 match self.width {
166 1.0 => write!(f, "k"),
167 w if w.fract() == 0.0 => write!(f, "{}k", w as u64),
168 w => write!(f, "{w}k"),
169 }
170 }
171}
172
173impl FromStr for RelativeKey {
174 type Err = DofError;
175
176 fn from_str(s: &str) -> Result<Self> {
177 match s.strip_suffix('k') {
178 Some(s) if !s.is_empty() => Ok(Self {
179 width: s.parse::<f64>()?,
180 has_key: true,
181 }),
182 Some(_) => Ok(Self {
183 width: 1.0,
184 has_key: true,
185 }),
186 None => Ok(Self {
187 width: s.parse::<f64>()?,
188 has_key: false,
189 }),
190 }
191 }
192}
193
194#[serde_as]
197#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
198pub struct RelativeKeyboard(#[serde_as(as = "Vec<RelativeKeyboardRow>")] Vec<Vec<RelativeKey>>);
199
200impl Keyboard for RelativeKeyboard {
201 type K = RelativeKey;
202
203 fn inner(&self) -> &[Vec<Self::K>] {
204 &self.0
205 }
206
207 fn into_inner(self) -> Vec<Vec<Self::K>> {
208 self.0
209 }
210}
211
212impl From<Vec<Vec<RelativeKey>>> for RelativeKeyboard {
213 fn from(v: Vec<Vec<RelativeKey>>) -> Self {
214 Self(v)
215 }
216}
217
218keyboard_conv!(RelativeKey, RelativeKeyboardRow);
219
220#[serde_as]
223#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
224pub struct NamedKeyboard {
225 #[serde_as(as = "DisplayFromStr")]
226 #[serde(rename = "type")]
227 pub(crate) form_factor: FormFactor,
228 pub(crate) anchor: Option<Anchor>,
229}
230
231impl TryFrom<FormFactor> for PhysicalKeyboard {
232 type Error = DofError;
233
234 fn try_from(form_factor: FormFactor) -> Result<Self> {
235 let kb = match form_factor {
236 FormFactor::Ansi => vec![
237 phys_row(&[(1.0, 1), (1.0, 12), (2.0, 1)], 0.0, 0.0),
238 phys_row(&[(1.5, 1), (1.0, 12), (1.5, 1)], 0.0, 1.0),
239 phys_row(&[(1.75, 1), (1.0, 11), (2.25, 1)], 0.0, 2.0),
240 phys_row(&[(2.25, 1), (1.0, 10), (2.75, 1)], 0.0, 3.0),
241 phys_row(&[(1.25, 3), (6.25, 1), (1.25, 4)], 0.0, 4.0),
242 ],
243 FormFactor::Iso => {
244 let mut iso = vec![
245 phys_row(&[(1.0, 1), (1.0, 12), (2.0, 1)], 0.0, 0.0),
246 phys_row(&[(1.5, 1), (1.0, 12) ], 0.0, 1.0),
247 phys_row(&[(1.75, 1), (1.0, 12) ], 0.0, 2.0),
248 phys_row(&[(1.25, 1), (1.0, 11), (2.75, 1)], 0.0, 3.0),
249 phys_row(&[(1.25, 3), (6.25, 1), (1.25, 4)], 0.0, 4.0),
250 ];
251
252 iso[1].push(PhysicalKey::xywh(13.75, 2.0, 1.5, 2.0));
254
255 iso
256 }
257 FormFactor::Ortho => vec![
258 phys_row(&[(1.0, 10)], 0.0, 0.0),
259 phys_row(&[(1.0, 10)], 0.0, 1.0),
260 phys_row(&[(1.0, 10)], 0.0, 2.0),
261 phys_row(&[(1.0, 6)], 2.0, 3.0),
262 ],
263 FormFactor::Colstag => vec![
264 vec![
265 PhysicalKey::xy(0.0, 0.45),
266 PhysicalKey::xy(1.0, 0.15),
267 PhysicalKey::xy(2.0, 0.0),
268 PhysicalKey::xy(3.0, 0.15),
269 PhysicalKey::xy(4.0, 0.30),
270 PhysicalKey::xy(7.0, 0.30),
271 PhysicalKey::xy(8.0, 0.15),
272 PhysicalKey::xy(9.0, 0.0),
273 PhysicalKey::xy(10.0, 0.15),
274 PhysicalKey::xy(11.0, 0.45),
275 ],
276 vec![
277 PhysicalKey::xy(0.0, 1.45),
278 PhysicalKey::xy(1.0, 1.15),
279 PhysicalKey::xy(2.0, 1.0),
280 PhysicalKey::xy(3.0, 1.15),
281 PhysicalKey::xy(4.0, 1.30),
282 PhysicalKey::xy(7.0, 1.30),
283 PhysicalKey::xy(8.0, 1.15),
284 PhysicalKey::xy(9.0, 1.0),
285 PhysicalKey::xy(10.0, 1.15),
286 PhysicalKey::xy(11.0, 1.45),
287 ],
288 vec![
289 PhysicalKey::xy(0.0, 2.45),
290 PhysicalKey::xy(1.0, 2.15),
291 PhysicalKey::xy(2.0, 2.0),
292 PhysicalKey::xy(3.0, 2.15),
293 PhysicalKey::xy(4.0, 2.30),
294 PhysicalKey::xy(7.0, 2.30),
295 PhysicalKey::xy(8.0, 2.15),
296 PhysicalKey::xy(9.0, 2.0),
297 PhysicalKey::xy(10.0, 2.15),
298 PhysicalKey::xy(11.0, 2.45),
299 ],
300 vec![
301 PhysicalKey::xy(2.4, 3.3),
302 PhysicalKey::xy(3.5, 3.5),
303 PhysicalKey::xy(4.7, 3.8),
304 PhysicalKey::xy(6.3, 3.8),
305 PhysicalKey::xy(7.5, 3.5),
306 PhysicalKey::xy(8.6, 3.3),
307 ],
308 ],
309 c @ FormFactor::Custom(_) => return Err(DE::UnknownKeyboardType(c).into()),
310 };
311
312 Ok(kb.into())
313 }
314}
315
316impl From<RelativeKeyboard> for PhysicalKeyboard {
317 fn from(rkb: RelativeKeyboard) -> Self {
318 rkb.into_inner()
319 .into_iter()
320 .enumerate()
321 .map(|(y, r)| {
322 let mut x = 0.0;
323
324 r.into_iter()
325 .filter_map(|rk| {
326 let r = PhysicalKey::xyw(x, y as f64, rk.width);
327 x += rk.width;
328 rk.has_key.then_some(r)
329 })
330 .collect()
331 })
332 .collect::<Vec<_>>()
333 .into()
334 }
335}
336
337impl From<PhysicalKeyboard> for ParseKeyboard {
338 fn from(board: PhysicalKeyboard) -> Self {
339 if board.inner().is_empty() {
340 return Self::Full(Default::default());
341 }
342
343 let relative_board = board
344 .rows()
345 .enumerate()
346 .map(|(row_i, r)| match r.split_first() {
347 None => Some(vec![]),
348 Some((f, r)) if f.y == row_i as f64 => {
349 let mut res = match f.x == 0.0 {
350 true => vec![RelativeKey {
351 width: f.width,
352 has_key: true,
353 }],
354 _ => vec![
355 RelativeKey {
356 width: f.x,
357 has_key: false,
358 },
359 RelativeKey {
360 width: f.width,
361 has_key: true,
362 },
363 ],
364 };
365
366 let mut last_x = f.width + f.x;
367
368 for key in r {
369 if key.y != row_i as f64 {
370 return None;
371 }
372 match key.x.total_cmp(&last_x) {
373 Ordering::Less => return None,
374 Ordering::Equal => res.push(RelativeKey {
375 width: key.width,
376 has_key: true,
377 }),
378 Ordering::Greater => {
379 res.push(RelativeKey {
380 width: key.x - last_x,
381 has_key: false,
382 });
383 res.push(RelativeKey {
384 width: key.width,
385 has_key: true,
386 });
387 }
388 }
389
390 last_x = key.x + key.width;
391 }
392
393 Some(res)
394 }
395 _ => None,
396 })
397 .collect::<Option<Vec<Vec<RelativeKey>>>>();
398
399 match relative_board {
400 Some(b) => Self::Relative(b.into()),
401 None => Self::Full(board),
402 }
403 }
404}
405
406#[serde_as]
414#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
415#[serde(untagged)]
416pub enum ParseKeyboard {
417 Named(#[serde_as(as = "DisplayFromStr")] FormFactor),
420 Relative(RelativeKeyboard),
423 Full(PhysicalKeyboard),
426}
427
428impl ParseKeyboard {
429 pub const fn anchor(&self) -> Anchor {
433 match self {
434 ParseKeyboard::Named(n) => n.anchor(),
435 _ => Anchor(0, 0),
436 }
437 }
438
439 pub fn fingering(&self, named_fingering: &NamedFingering) -> Result<Fingering> {
444 match self {
445 ParseKeyboard::Named(n) => n.fingering(named_fingering),
446 _ => Err(DE::FingeringForCustomKeyboard.into()),
447 }
448 }
449}
450
451impl TryFrom<ParseKeyboard> for PhysicalKeyboard {
452 type Error = DofError;
453
454 fn try_from(value: ParseKeyboard) -> Result<Self> {
455 match value {
456 ParseKeyboard::Named(board) => board.try_into(),
457 ParseKeyboard::Relative(r) => Ok(r.into()),
458 ParseKeyboard::Full(f) => Ok(f),
459 }
460 }
461}
462
463pub(crate) fn phys_row(widths: &[(f64, usize)], x_offset: f64, y_offset: f64) -> Vec<PhysicalKey> {
464 let mut x = x_offset;
465
466 widths
467 .iter()
468 .copied()
469 .flat_map(|(width, count)| std::iter::repeat_n(width, count))
470 .map(|w| {
471 let pk = PhysicalKey::xyw(x, y_offset, w);
472 x += w;
473 pk
474 })
475 .collect()
476}
477
478#[cfg(test)]
479mod tests {
480 use super::*;
481 use assert_matches::assert_matches;
482
483 #[test]
484 fn parse_physical_key() {
485 let k1 = "0.0 0.0".parse::<PhysicalKey>();
486 let k2 = "1 2 3".parse::<PhysicalKey>();
487 let k3 = "0 0 4 2".parse::<PhysicalKey>();
488 let k4 = "0.1".parse::<PhysicalKey>();
489 let k5 = "0.1 0.2".parse::<PhysicalKey>();
490 let k6 = "".parse::<PhysicalKey>();
491
492 assert_eq!(k1, Ok(PhysicalKey::xy(0.0, 0.0)));
493 assert_eq!(k2, Ok(PhysicalKey::xywh(1.0, 2.0, 3.0, 1.0)));
494 assert_eq!(k3, Ok(PhysicalKey::xywh(0.0, 0.0, 4.0, 2.0)));
495 assert_eq!(
496 k4,
497 Err(DofError::from(DE::ValueAmountError(1, "0.1".into())))
498 );
499 assert_eq!(k5, Ok(PhysicalKey::xy(0.1, 0.2)));
500 assert_eq!(k6, Err(DofError::from(DE::EmptyPhysKey)));
501 }
502
503 #[test]
504 fn parse_physical_key_board() {
505 let board_str = r#"[
506 [
507 "1.8125 0.5 2 3"
508 ]
509 ]
510 "#;
511
512 let kb = serde_json::from_str::<PhysicalKeyboard>(board_str)
513 .expect("parsing of Keyboard failed");
514
515 let cmp = PhysicalKeyboard(vec![vec![PhysicalKey {
516 x: 1.8125,
517 y: 0.5,
518 width: 2.0,
519 height: 3.0,
520 }]]);
521
522 assert_eq!(kb, cmp);
523
524 let parsed = ParseKeyboard::from(kb);
525
526 assert_matches!(parsed, ParseKeyboard::Full(_))
527 }
528
529 #[test]
530 fn parse_relative_key() {
531 let k1 = "k".parse::<RelativeKey>();
532 let k2 = "2.3k".parse::<RelativeKey>();
533 let k3 = "5".parse::<RelativeKey>();
534 let k4 = "".parse::<RelativeKey>();
535
536 assert_eq!(
537 k1,
538 Ok(RelativeKey {
539 width: 1.0,
540 has_key: true
541 })
542 );
543 assert_eq!(
544 k2,
545 Ok(RelativeKey {
546 width: 2.3,
547 has_key: true
548 })
549 );
550 assert_eq!(
551 k3,
552 Ok(RelativeKey {
553 width: 5.0,
554 has_key: false
555 })
556 );
557
558 match k4 {
559 Ok(_) => panic!("Should be a `ParseFloatError`, actually: '{k4:?}'"),
560 Err(e) => assert!(matches!(e.0.as_ref(), DE::ParseFloatError(_))),
561 }
562 }
563
564 #[test]
565 fn row_defined_keyboard() {
566 let board_str = r#"
567 [
568 "k 3.2k 2 8k"
569 ]
570 "#;
571
572 let kb = serde_json::from_str::<ParseKeyboard>(board_str)
573 .expect("parsing of RelativeKeyboard failed");
574
575 let cmp = ParseKeyboard::Relative(RelativeKeyboard(vec![vec![
576 RelativeKey {
577 width: 1.0,
578 has_key: true,
579 },
580 RelativeKey {
581 width: 3.2,
582 has_key: true,
583 },
584 RelativeKey {
585 width: 2.0,
586 has_key: false,
587 },
588 RelativeKey {
589 width: 8.0,
590 has_key: true,
591 },
592 ]]));
593
594 assert_eq!(kb, cmp);
595
596 let keyboard = PhysicalKeyboard::try_from(cmp)
597 .expect("couldn't convert to physical keyboard from parse keyboard: ");
598
599 let parsed = ParseKeyboard::from(keyboard);
600
601 println!("{parsed:?}");
602
603 assert_matches!(parsed, ParseKeyboard::Relative(_))
604 }
605
606 #[test]
607 fn named_parsed_keyboard() {
608 let board_str = "\"ansi\"";
609
610 let board = serde_json::from_str::<ParseKeyboard>(board_str)
611 .expect("parsing of ParseKeyboard failed");
612
613 assert_eq!(board, ParseKeyboard::Named(FormFactor::Ansi));
614
615 let kb = PhysicalKeyboard::try_from(board)
616 .expect("error encountered while converting to physical keyboard: ")
617 .resized(FormFactor::Ansi.anchor(), vec![10, 11, 10].into());
618
619 let cmp = &PhysicalKey {
620 x: 11.25,
621 y: 3.0,
622 width: 1.0,
623 height: 1.0,
624 };
625
626 match kb {
627 Ok(kb) => match kb.last() {
628 Some(r) => match r.last() {
629 Some(k) => assert_eq!(k, cmp),
630 None => panic!("Row has no keys"),
631 },
632 None => panic!("Keyboard is empty"),
633 },
634 Err(e) => panic!("{:?}", e),
635 }
636 }
637
638 #[test]
639 fn rows_parsed_keyboard() {
640 let board_str = r#"[
641 "1 k k k 2 k k k 1",
642 "k k k k 2 k k k k",
643 " 3 k k k k 3 "
644 ]"#;
645
646 let board: PhysicalKeyboard = serde_json::from_str::<ParseKeyboard>(board_str)
647 .expect("parsing of ParseKeyboard failed")
648 .try_into()
649 .expect("error encountered while converting to physical keyboard: ");
650
651 assert_eq!(board.inner()[0].len(), 6);
652 assert_eq!(board.inner()[2].len(), 4);
653 assert_eq!(board.inner()[0][3].x, 6.0);
654 }
655}