hex_patch/app/settings/
register_key_settings_macro.rs

1use 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}