veloren_voxygen/settings/
control.rs1use crate::{game_input::GameInput, window::KeyMouse};
2use hashbrown::{HashMap, HashSet};
3use serde::{Deserialize, Serialize};
4use strum::IntoEnumIterator;
5use winit::{
6 event::MouseButton,
7 keyboard::{Key, NamedKey},
8};
9
10#[derive(Serialize, Deserialize)]
13struct ControlSettingsSerde {
14 keybindings: HashMap<GameInput, Option<KeyMouse>>,
15}
16
17impl From<ControlSettings> for ControlSettingsSerde {
18 fn from(control_settings: ControlSettings) -> Self {
19 let mut user_bindings: HashMap<GameInput, Option<KeyMouse>> = HashMap::new();
20 for (k, v) in control_settings.keybindings {
23 if ControlSettings::default_binding(k) != v {
24 user_bindings.insert(k, v);
26 }
27 }
28 ControlSettingsSerde {
29 keybindings: user_bindings,
30 }
31 }
32}
33
34#[derive(Clone, Debug, Serialize, Deserialize)]
36#[serde(from = "ControlSettingsSerde", into = "ControlSettingsSerde")]
37pub struct ControlSettings {
38 pub keybindings: HashMap<GameInput, Option<KeyMouse>>,
39 pub inverse_keybindings: HashMap<KeyMouse, HashSet<GameInput>>, }
41
42impl From<ControlSettingsSerde> for ControlSettings {
43 fn from(control_serde: ControlSettingsSerde) -> Self {
44 let user_keybindings = control_serde.keybindings;
45 let mut control_settings = ControlSettings::default();
46 for (k, maybe_v) in user_keybindings {
47 match maybe_v {
48 Some(v) => control_settings.modify_binding(k, v),
49 None => control_settings.remove_binding(k),
50 }
51 }
52 control_settings
53 }
54}
55
56#[cfg(target_os = "macos")]
62const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Key(Key::Named(NamedKey::Shift));
63#[cfg(not(target_os = "macos"))]
64const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
65
66impl ControlSettings {
67 pub fn remove_binding(&mut self, game_input: GameInput) {
68 if let Some(inverse) = self
69 .keybindings
70 .insert(game_input, None)
71 .flatten()
72 .and_then(|key_mouse| self.inverse_keybindings.get_mut(&key_mouse))
73 {
74 inverse.remove(&game_input);
75 }
76 }
77
78 pub fn get_binding(&self, game_input: GameInput) -> Option<KeyMouse> {
79 self.keybindings.get(&game_input).cloned().flatten()
80 }
81
82 pub fn get_associated_game_inputs(&self, key_mouse: &KeyMouse) -> Option<&HashSet<GameInput>> {
83 self.inverse_keybindings.get(key_mouse)
84 }
85
86 pub fn insert_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
87 self.keybindings.insert(game_input, Some(key_mouse.clone()));
88 self.inverse_keybindings
89 .entry(key_mouse)
90 .or_default()
91 .insert(game_input);
92 }
93
94 pub fn modify_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
95 if let Some(old_binding) = self.get_binding(game_input) {
98 self.inverse_keybindings
99 .entry(old_binding)
100 .or_default()
101 .remove(&game_input);
102 }
103 self.inverse_keybindings
105 .entry(key_mouse.clone())
106 .or_default()
107 .insert(game_input);
108 self.keybindings.insert(game_input, Some(key_mouse));
110 }
111
112 pub fn has_conflicting_bindings(&self, key_mouse: KeyMouse) -> bool {
115 if let Some(game_inputs) = self.inverse_keybindings.get(&key_mouse) {
116 for a in game_inputs.iter() {
117 for b in game_inputs.iter() {
118 if !GameInput::can_share_bindings(*a, *b) {
119 return true;
120 }
121 }
122 }
123 }
124 false
125 }
126
127 pub fn default_binding(game_input: GameInput) -> Option<KeyMouse> {
128 let char = |s| Key::Character(winit::keyboard::SmolStr::new(s));
129
130 Some(KeyMouse::Key(match game_input {
132 GameInput::Primary => return Some(KeyMouse::Mouse(MouseButton::Left)),
133 GameInput::Secondary => return Some(KeyMouse::Mouse(MouseButton::Right)),
134 GameInput::Block => Key::Named(NamedKey::Alt),
135 GameInput::ToggleCursor => char(","),
136 GameInput::Escape => Key::Named(NamedKey::Escape),
137 GameInput::Chat => Key::Named(NamedKey::Enter),
138 GameInput::Command => char("/"),
139 GameInput::MoveForward => char("W"),
140 GameInput::MoveLeft => char("A"),
141 GameInput::MoveBack => char("S"),
142 GameInput::MoveRight => char("D"),
143 GameInput::Jump => Key::Named(NamedKey::Space),
144 GameInput::WallJump => Key::Named(NamedKey::Space),
145 GameInput::Sit => char("K"),
146 GameInput::Crawl => Key::Named(NamedKey::ArrowDown),
147 GameInput::Dance => char("J"),
148 GameInput::Greet => char("H"),
149 GameInput::Glide => Key::Named(NamedKey::Control),
150 GameInput::SwimUp => Key::Named(NamedKey::Space),
151 GameInput::SwimDown => Key::Named(NamedKey::Shift),
152 GameInput::Fly => char("H"),
153 GameInput::Sneak => Key::Named(NamedKey::Shift),
154 GameInput::CancelClimb => Key::Named(NamedKey::Shift),
155 GameInput::ToggleLantern => char("G"),
156 GameInput::Mount => char("F"),
157 GameInput::StayFollow => char("V"),
158 GameInput::Map => char("M"),
159 GameInput::Inventory => char("I"),
160 GameInput::Trade => char("T"),
161 GameInput::Social => char("O"),
162 GameInput::Crafting => char("C"),
163 GameInput::Diary => char("P"),
164 GameInput::Settings => Key::Named(NamedKey::F10),
165 GameInput::Controls => Key::Named(NamedKey::F1),
166 GameInput::ToggleInterface => Key::Named(NamedKey::F2),
167 GameInput::ToggleDebug => Key::Named(NamedKey::F3),
168 #[cfg(feature = "egui-ui")]
169 GameInput::ToggleEguiDebug => Key::Named(NamedKey::F7),
170 GameInput::ToggleChat => Key::Named(NamedKey::F5),
171 GameInput::Fullscreen => Key::Named(NamedKey::F11),
172 GameInput::Screenshot => Key::Named(NamedKey::F4),
173 GameInput::ToggleIngameUi => Key::Named(NamedKey::F6),
174 GameInput::Roll => return Some(MIDDLE_CLICK_KEY),
175 GameInput::GiveUp => Key::Named(NamedKey::Space),
176 GameInput::Respawn => Key::Named(NamedKey::Space),
177 GameInput::Interact => char("E"),
178 GameInput::ToggleWield => char("R"),
179 GameInput::FreeLook => char("L"),
180 GameInput::AutoWalk => char("."),
181 GameInput::ZoomIn => char(")"),
182 GameInput::ZoomOut => char("("),
183 GameInput::ZoomLock => return None,
184 GameInput::CameraClamp => char("'"),
185 GameInput::CycleCamera => char("0"),
186 GameInput::Slot1 => char("1"),
187 GameInput::Slot2 => char("2"),
188 GameInput::Slot3 => char("3"),
189 GameInput::Slot4 => char("4"),
190 GameInput::Slot5 => char("5"),
191 GameInput::Slot6 => char("6"),
192 GameInput::Slot7 => char("7"),
193 GameInput::Slot8 => char("8"),
194 GameInput::Slot9 => char("9"),
195 GameInput::Slot10 => char("Q"),
196 GameInput::SwapLoadout => Key::Named(NamedKey::Tab),
197 GameInput::Select => char("X"),
198 GameInput::AcceptGroupInvite => char("Y"),
199 GameInput::DeclineGroupInvite => char("N"),
200 GameInput::MapZoomIn => char("+"),
201 GameInput::MapZoomOut => char("-"),
202 GameInput::MapSetMarker => return Some(KeyMouse::Mouse(MouseButton::Middle)),
203 GameInput::SpectateSpeedBoost => Key::Named(NamedKey::Control),
204 GameInput::SpectateViewpoint => return Some(KeyMouse::Mouse(MouseButton::Middle)),
205 GameInput::MuteMaster => Key::Named(NamedKey::AudioVolumeMute),
206 GameInput::MuteInactiveMaster => return None,
207 GameInput::MuteMusic => Key::Named(NamedKey::F8),
208 GameInput::MuteSfx => return None,
209 GameInput::MuteAmbience => return None,
210 GameInput::ToggleWalk => char("B"),
211 }))
212 }
213}
214
215impl Default for ControlSettings {
216 fn default() -> Self {
217 let mut new_settings = Self {
218 keybindings: HashMap::new(),
219 inverse_keybindings: HashMap::new(),
220 };
221 for game_input in GameInput::iter() {
223 match ControlSettings::default_binding(game_input) {
224 None => {},
225 Some(default) => new_settings.insert_binding(game_input, default),
226 };
227 }
228 new_settings
229 }
230}