hex_patch/app/settings/
register_key_settings_macro.rs1use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, MouseEvent};
2use mlua::{Lua, Table};
3
4use crate::app::plugins::ui_location::ui_location::UiLocation;
5
6use super::key_settings::KeySettings;
7
8#[macro_export]
9macro_rules! RegisterKeySettings {(
10 $(#[$attr:meta])*
11 $pub:vis struct $key_settings:ident {
12 $(
13 $(#[$field_attr:meta])*
14 $field_pub:vis $field_name:ident: $field_type:ty,
15 )*
16 }) => {
17 impl $key_settings
18 {
19 pub fn register_userdata(data: &mut mlua::UserDataRegistry<$crate::app::settings::Settings>)
20 {
21 $(
22 mlua::UserDataFields::add_field_method_get(data, concat!("key_",stringify!($field_name)), |lua, settings| {
23 $crate::app::settings::register_key_settings_macro::
24 get_key(lua, &settings.key.$field_name)
25 });
26 mlua::UserDataFields::add_field_method_set(data, concat!("key_",stringify!($field_name)), |lua, settings, value| {
27 $crate::app::settings::register_key_settings_macro::
28 set_key(lua, &mut settings.key.$field_name, value)
29 });
30 )*
31 }
32 }
33 };
34}
35
36fn key_modifiers_to_table(lua: &Lua, modifiers: KeyModifiers) -> mlua::Result<Table> {
37 let ret = lua.create_table()?;
38 ret.set("alt", modifiers.contains(KeyModifiers::ALT))?;
39 ret.set("control", modifiers.contains(KeyModifiers::CONTROL))?;
40 ret.set("hyper", modifiers.contains(KeyModifiers::HYPER))?;
41 ret.set("meta", modifiers.contains(KeyModifiers::META))?;
42 ret.set("shift", modifiers.contains(KeyModifiers::SHIFT))?;
43 ret.set("super", modifiers.contains(KeyModifiers::SUPER))?;
44 Ok(ret)
45}
46
47fn key_state_to_table(lua: &Lua, state: KeyEventState) -> mlua::Result<Table> {
48 let ret = lua.create_table()?;
49 ret.set("caps_lock", state.contains(KeyEventState::CAPS_LOCK))?;
50 ret.set("keypad", state.contains(KeyEventState::KEYPAD))?;
51 ret.set("num_lock", state.contains(KeyEventState::NUM_LOCK))?;
52 Ok(ret)
53}
54
55pub fn mouse_event_to_lua(
56 lua: &Lua,
57 mouse: &MouseEvent,
58 location: Option<UiLocation>,
59) -> mlua::Result<Table> {
60 let ret = lua.create_table()?;
61 ret.set("kind", format!("{:?}", mouse.kind))?;
62 ret.set("column", mouse.column)?;
63 ret.set("row", mouse.row)?;
64
65 let modifiers = key_modifiers_to_table(lua, mouse.modifiers)?;
66 ret.set("modifiers", modifiers)?;
67 ret.set("location", location)?;
68 Ok(ret)
69}
70
71pub fn key_event_to_lua(lua: &Lua, key: &KeyEvent) -> mlua::Result<Table> {
72 let ret = lua.create_table()?;
73 ret.set("code", KeySettings::key_code_to_string(key.code))?;
74
75 let modifiers = key_modifiers_to_table(lua, key.modifiers)?;
76 ret.set("modifiers", modifiers)?;
77
78 ret.set("kind", format!("{:?}", key.kind))?;
79
80 let state = key_state_to_table(lua, key.state)?;
81 ret.set("state", state)?;
82
83 Ok(ret)
84}
85
86pub fn lua_to_key_event(_lua: &Lua, table: &mlua::Table) -> mlua::Result<KeyEvent> {
87 let code = match table.get::<String>("code") {
88 Ok(value) => KeySettings::string_to_key_code(&value).map_err(mlua::Error::RuntimeError)?,
89 Err(e) => match e {
90 mlua::Error::FromLuaConversionError {
91 from: "nil",
92 to,
93 message: _,
94 } if to == "String" => KeyCode::Null,
95 _ => return Err(e),
96 },
97 };
98
99 let mut modifiers = KeyModifiers::NONE;
100 if let Ok(modifiers_table) = table.get::<Table>("modifiers") {
101 if modifiers_table.get::<bool>("alt").unwrap_or(false) {
102 modifiers |= KeyModifiers::ALT;
103 }
104 if modifiers_table.get::<bool>("control").unwrap_or(false) {
105 modifiers |= KeyModifiers::CONTROL;
106 }
107 if modifiers_table.get::<bool>("hyper").unwrap_or(false) {
108 modifiers |= KeyModifiers::HYPER;
109 }
110 if modifiers_table.get::<bool>("meta").unwrap_or(false) {
111 modifiers |= KeyModifiers::META;
112 }
113 if modifiers_table.get::<bool>("shift").unwrap_or(false) {
114 modifiers |= KeyModifiers::SHIFT;
115 }
116 if modifiers_table.get::<bool>("super").unwrap_or(false) {
117 modifiers |= KeyModifiers::SUPER;
118 }
119 }
120
121 let kind = match table.get::<String>("kind") {
122 Ok(value) => {
123 KeySettings::string_to_key_event_kind(&value).map_err(mlua::Error::RuntimeError)?
124 }
125 Err(e) => match e {
126 mlua::Error::FromLuaConversionError {
127 from: "nil",
128 to,
129 message: _,
130 } if to == "String" => KeyEventKind::Press,
131 _ => return Err(e),
132 },
133 };
134
135 let mut state = KeyEventState::NONE;
136 if let Ok(state_table) = table.get::<Table>("state") {
137 if state_table.get::<bool>("caps_lock").unwrap_or(false) {
138 state |= KeyEventState::CAPS_LOCK;
139 }
140 if state_table.get::<bool>("keypad").unwrap_or(false) {
141 state |= KeyEventState::KEYPAD;
142 }
143 if state_table.get::<bool>("num_lock").unwrap_or(false) {
144 state |= KeyEventState::NUM_LOCK;
145 }
146 }
147
148 Ok(KeyEvent {
149 code,
150 modifiers,
151 kind,
152 state,
153 })
154}
155
156pub(super) fn get_key(lua: &Lua, key: &KeyEvent) -> mlua::Result<mlua::Value> {
157 key_event_to_lua(lua, key).map(mlua::Value::Table)
158}
159
160pub(super) fn set_key(lua: &Lua, color: &mut KeyEvent, value: mlua::Value) -> mlua::Result<()> {
161 if let Some(table) = value.as_table() {
162 *color = lua_to_key_event(lua, table)?;
163 Ok(())
164 } else {
165 Err(mlua::Error::RuntimeError("Expected table".to_string()))
166 }
167}