mod.rs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. use std::{collections::HashMap, ffi::OsStr, fs::read_to_string, path::PathBuf};
  2. use crate::{
  3. application::{mode::ModeKey, Application},
  4. errors::*,
  5. };
  6. use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyModifiers};
  7. use linked_hash_map::LinkedHashMap;
  8. use smallvec::SmallVec;
  9. use strum::IntoEnumIterator;
  10. use yaml_rust::{Yaml, YamlLoader};
  11. const INPUT_CONFIG_NAME: &str = "input.yaml";
  12. pub struct InputLoader;
  13. impl InputLoader {
  14. pub fn load(
  15. path: PathBuf,
  16. ) -> Result<HashMap<String, HashMap<String, SmallVec<[fn(&mut Application) -> Result<()>; 4]>>>>
  17. {
  18. #[cfg(not(feature = "dragonos"))]
  19. let data = Self::load_user(path)?;
  20. #[cfg(feature = "dragonos")]
  21. let data = None;
  22. let default = Self::load_default()?;
  23. let handle_map = Self::generate_handle_map(
  24. data,
  25. default
  26. .as_hash()
  27. .ok_or_else(|| "default input config didn't return a hash of key bindings")?,
  28. )?;
  29. Ok(handle_map)
  30. }
  31. fn generate_handle_map(
  32. extra_data: Option<LinkedHashMap<Yaml, Yaml>>,
  33. default: &LinkedHashMap<Yaml, Yaml>,
  34. ) -> Result<HashMap<String, HashMap<String, SmallVec<[fn(&mut Application) -> Result<()>; 4]>>>>
  35. {
  36. let mut handle_map = HashMap::new();
  37. for mode_key in ModeKey::iter() {
  38. mode_key.generate_handle_map(&mut handle_map, extra_data.as_ref(), default)?;
  39. }
  40. Ok(handle_map)
  41. }
  42. fn load_user(path: PathBuf) -> Result<Option<LinkedHashMap<Yaml, Yaml>>> {
  43. let readdir = path.read_dir()?;
  44. let mut entries = readdir
  45. .filter_map(|f| f.ok())
  46. .map(|f| f.path())
  47. .filter(|f| f.is_file())
  48. .filter(|f| {
  49. f.file_name().is_some() && f.file_name().unwrap() == OsStr::new(INPUT_CONFIG_NAME)
  50. });
  51. let entry = entries.next();
  52. if let Some(entry) = entry {
  53. let yaml = YamlLoader::load_from_str(&read_to_string(entry.clone())?)
  54. .chain_err(|| format!("Couldn't parse input config file: {:?}", entry))?
  55. .into_iter()
  56. .next()
  57. .chain_err(|| "No input document found")?;
  58. let yaml_hash = yaml
  59. .as_hash()
  60. .ok_or_else(|| "extra input config didn't return a hash of key bindings")?;
  61. return Ok(Some(yaml_hash.clone()));
  62. }
  63. Ok(None)
  64. }
  65. fn load_default() -> Result<Yaml> {
  66. YamlLoader::load_from_str(include_str!("default.yaml"))
  67. .chain_err(|| "Couldn't parse default input config file")?
  68. .into_iter()
  69. .next()
  70. .chain_err(|| "No default input document found")
  71. }
  72. }
  73. pub struct InputMapper;
  74. impl InputMapper {
  75. pub fn event_map_str(event: Event) -> Option<String> {
  76. match event {
  77. Event::FocusGained => None,
  78. Event::FocusLost => None,
  79. Event::Key(key_event) => {
  80. return Some(Self::key_event_map_str(key_event));
  81. }
  82. Event::Mouse(_) => None,
  83. Event::Paste(_) => None,
  84. Event::Resize(_, _) => None,
  85. }
  86. }
  87. fn key_event_map_str(event: KeyEvent) -> String {
  88. if let KeyEventKind::Press = event.kind {
  89. let mut modifier = String::new();
  90. if event.modifiers.contains(KeyModifiers::CONTROL) {
  91. modifier.push_str("ctrl-");
  92. }
  93. if event.modifiers.contains(KeyModifiers::ALT) {
  94. modifier.push_str("alt-");
  95. }
  96. if event.modifiers.contains(KeyModifiers::SHIFT) {
  97. modifier.push_str("shift-");
  98. }
  99. let keycode_str = match event.code {
  100. crossterm::event::KeyCode::Backspace => "backspace".into(),
  101. crossterm::event::KeyCode::Enter => "enter".into(),
  102. crossterm::event::KeyCode::Left => "left".into(),
  103. crossterm::event::KeyCode::Right => "right".into(),
  104. crossterm::event::KeyCode::Up => "up".into(),
  105. crossterm::event::KeyCode::Down => "down".into(),
  106. crossterm::event::KeyCode::Home => "home".into(),
  107. crossterm::event::KeyCode::End => "end".into(),
  108. crossterm::event::KeyCode::PageUp => "pageup".into(),
  109. crossterm::event::KeyCode::PageDown => "pagedown".into(),
  110. crossterm::event::KeyCode::Tab => "tab".into(),
  111. crossterm::event::KeyCode::BackTab => "backtab".into(),
  112. crossterm::event::KeyCode::Delete => "delete".into(),
  113. crossterm::event::KeyCode::Insert => "insert".into(),
  114. crossterm::event::KeyCode::F(f) => format!("f{f}"),
  115. crossterm::event::KeyCode::Char(c) => {
  116. if c.is_digit(10) {
  117. "num".to_string()
  118. } else {
  119. c.into()
  120. }
  121. }
  122. crossterm::event::KeyCode::Null => "".into(),
  123. crossterm::event::KeyCode::Esc => "escape".into(),
  124. crossterm::event::KeyCode::CapsLock => "caps_lock".into(),
  125. crossterm::event::KeyCode::ScrollLock => "scroll_lock".into(),
  126. crossterm::event::KeyCode::NumLock => "num_lock".into(),
  127. crossterm::event::KeyCode::PrintScreen => "print_screen".into(),
  128. crossterm::event::KeyCode::Pause => "pause".into(),
  129. crossterm::event::KeyCode::Menu => "menu".into(),
  130. crossterm::event::KeyCode::KeypadBegin => "keypad_begin".into(),
  131. crossterm::event::KeyCode::Media(_) => "".into(),
  132. crossterm::event::KeyCode::Modifier(modifier_key_code) => match modifier_key_code {
  133. crossterm::event::ModifierKeyCode::LeftShift
  134. | crossterm::event::ModifierKeyCode::IsoLevel3Shift
  135. | crossterm::event::ModifierKeyCode::IsoLevel5Shift
  136. | crossterm::event::ModifierKeyCode::RightShift => "shift".into(),
  137. crossterm::event::ModifierKeyCode::LeftControl
  138. | crossterm::event::ModifierKeyCode::RightControl => "ctrl".into(),
  139. crossterm::event::ModifierKeyCode::LeftAlt
  140. | crossterm::event::ModifierKeyCode::RightAlt => "alt".into(),
  141. crossterm::event::ModifierKeyCode::RightSuper
  142. | crossterm::event::ModifierKeyCode::LeftSuper => "super".into(),
  143. crossterm::event::ModifierKeyCode::RightHyper
  144. | crossterm::event::ModifierKeyCode::LeftHyper => "hyper".into(),
  145. crossterm::event::ModifierKeyCode::RightMeta
  146. | crossterm::event::ModifierKeyCode::LeftMeta => "meta".into(),
  147. },
  148. };
  149. format!("{}{}", modifier, keycode_str)
  150. } else {
  151. "".into()
  152. }
  153. }
  154. }