mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Carbonhell/keybindings
This commit is contained in:
parent
611359e52f
commit
198c875559
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added daily Mac builds
|
- Added daily Mac builds
|
||||||
- Allow spawning individual pet species, not just generic body kinds.
|
- Allow spawning individual pet species, not just generic body kinds.
|
||||||
- Configurable fonts
|
- Configurable fonts
|
||||||
|
- Configurable keybindings from the Controls menu
|
||||||
- Tanslation status tracking
|
- Tanslation status tracking
|
||||||
- Added gamma setting
|
- Added gamma setting
|
||||||
- Added new orc hairstyles
|
- Added new orc hairstyles
|
||||||
|
@ -250,90 +250,7 @@ Enjoy your stay in the World of Veloren."#,
|
|||||||
"hud.settings.sound_effect_volume": "Sound Effects Volume",
|
"hud.settings.sound_effect_volume": "Sound Effects Volume",
|
||||||
"hud.settings.audio_device": "Audio Device",
|
"hud.settings.audio_device": "Audio Device",
|
||||||
|
|
||||||
// Control list
|
"hud.settings.awaitingkey": "Press a key...",
|
||||||
"hud.settings.control_names": r#"Free Cursor
|
|
||||||
Toggle Help Window
|
|
||||||
Toggle Interface
|
|
||||||
Toggle FPS and Debug Info
|
|
||||||
Take Screenshot
|
|
||||||
Toggle Nametags
|
|
||||||
Toggle Fullscreen
|
|
||||||
|
|
||||||
|
|
||||||
Move Forward
|
|
||||||
Move Left
|
|
||||||
Move Right
|
|
||||||
Move Backwards
|
|
||||||
|
|
||||||
Jump
|
|
||||||
|
|
||||||
Glider
|
|
||||||
|
|
||||||
Dodge
|
|
||||||
|
|
||||||
Roll
|
|
||||||
|
|
||||||
Climb
|
|
||||||
|
|
||||||
Climb down
|
|
||||||
|
|
||||||
Auto Walk
|
|
||||||
|
|
||||||
Sheathe/Draw Weapons
|
|
||||||
|
|
||||||
Put on/Remove Helmet
|
|
||||||
|
|
||||||
Sit
|
|
||||||
|
|
||||||
Mount
|
|
||||||
|
|
||||||
Interact
|
|
||||||
|
|
||||||
|
|
||||||
Basic Attack
|
|
||||||
Secondary Attack/Block/Aim
|
|
||||||
|
|
||||||
|
|
||||||
Skillbar Slot 1
|
|
||||||
Skillbar Slot 2
|
|
||||||
Skillbar Slot 3
|
|
||||||
Skillbar Slot 4
|
|
||||||
Skillbar Slot 5
|
|
||||||
Skillbar Slot 6
|
|
||||||
Skillbar Slot 7
|
|
||||||
Skillbar Slot 8
|
|
||||||
Skillbar Slot 9
|
|
||||||
Skillbar Slot 10
|
|
||||||
|
|
||||||
|
|
||||||
Pause Menu
|
|
||||||
Settings
|
|
||||||
Social
|
|
||||||
Map
|
|
||||||
Spellbook
|
|
||||||
Character
|
|
||||||
Questlog
|
|
||||||
Bag
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Send Chat Message
|
|
||||||
Scroll Chat
|
|
||||||
|
|
||||||
|
|
||||||
Free look
|
|
||||||
|
|
||||||
|
|
||||||
Chat commands:
|
|
||||||
|
|
||||||
/alias [Name] - Change your Chat Name
|
|
||||||
/tp [Name] - Teleports you to another player
|
|
||||||
/jump <dx> <dy> <dz> - Offset your position
|
|
||||||
/goto <x> <y> <z> - Teleport to a position
|
|
||||||
/kill - Kill yourself
|
|
||||||
/pig - Spawn pig NPC
|
|
||||||
/wolf - Spawn wolf NPC
|
|
||||||
/help - Display chat commands"#,
|
|
||||||
|
|
||||||
"hud.social": "Social",
|
"hud.social": "Social",
|
||||||
"hud.social.online": "Online",
|
"hud.social.online": "Online",
|
||||||
@ -348,6 +265,48 @@ Chat commands:
|
|||||||
/// End HUD section
|
/// End HUD section
|
||||||
|
|
||||||
|
|
||||||
|
/// Start GameInput section
|
||||||
|
|
||||||
|
"gameinput.primary": "Basic Attack",
|
||||||
|
"gameinput.secondary": "Secondary Attack/Block/Aim",
|
||||||
|
"gameinput.ability3": "Hotbar Slot 1",
|
||||||
|
"gameinput.swaploadout": "Swap Loadout",
|
||||||
|
"gameinput.togglecursor": "Free Cursor",
|
||||||
|
"gameinput.help": "Toggle Help Window",
|
||||||
|
"gameinput.toggleinterface": "Toggle Interface",
|
||||||
|
"gameinput.toggledebug": "Toggle FPS and Debug Info",
|
||||||
|
"gameinput.screenshot": "Take Screenshot",
|
||||||
|
"gameinput.toggleingameui": "Toggle Nametags",
|
||||||
|
"gameinput.fullscreen": "Toggle Fullscreen",
|
||||||
|
"gameinput.moveforward": "Move Forward",
|
||||||
|
"gameinput.moveleft": "Move Left",
|
||||||
|
"gameinput.moveright": "Move Right",
|
||||||
|
"gameinput.moveback": "Move Backwards",
|
||||||
|
"gameinput.jump": "Jump",
|
||||||
|
"gameinput.glide": "Glider",
|
||||||
|
"gameinput.roll": "Roll",
|
||||||
|
"gameinput.climb": "Climb",
|
||||||
|
"gameinput.climbdown": "Climb Down",
|
||||||
|
"gameinput.wallleap": "Wall Leap",
|
||||||
|
"gameinput.mount": "Mount",
|
||||||
|
"gameinput.enter": "Enter",
|
||||||
|
"gameinput.command": "Command",
|
||||||
|
"gameinput.escape": "Escape",
|
||||||
|
"gameinput.map": "Map",
|
||||||
|
"gameinput.bag": "Bag",
|
||||||
|
"gameinput.social": "Social",
|
||||||
|
"gameinput.sit": "Sit",
|
||||||
|
"gameinput.spellbook": "Spell Book",
|
||||||
|
"gameinput.settings": "Settings",
|
||||||
|
"gameinput.respawn": "Respawn",
|
||||||
|
"gameinput.charge": "Charge",
|
||||||
|
"gameinput.togglewield": "Toggle Wield",
|
||||||
|
"gameinput.interact": "Interact",
|
||||||
|
"gameinput.freelook": "Free look behavior",
|
||||||
|
|
||||||
|
/// End GameInput section
|
||||||
|
|
||||||
|
|
||||||
/// Start chracter selection section
|
/// Start chracter selection section
|
||||||
"char_selection.delete_permanently": "Permanently delete this Character?",
|
"char_selection.delete_permanently": "Permanently delete this Character?",
|
||||||
"char_selection.change_server": "Change Server",
|
"char_selection.change_server": "Change Server",
|
||||||
|
@ -237,6 +237,7 @@ pub enum Event {
|
|||||||
Logout,
|
Logout,
|
||||||
Quit,
|
Quit,
|
||||||
ChangeLanguage(LanguageMetadata),
|
ChangeLanguage(LanguageMetadata),
|
||||||
|
ChangeBinding(GameInput),
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
ChangeFreeLookBehavior(PressBehavior),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1494,60 +1495,63 @@ impl Hud {
|
|||||||
.set(self.ids.num_figures, ui_widgets);
|
.set(self.ids.num_figures, ui_widgets);
|
||||||
|
|
||||||
// Help Window
|
// Help Window
|
||||||
|
if let Some(help_key) = global_state.settings.controls.get_binding(GameInput::Help) {
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
.voxygen_i18n
|
.voxygen_i18n
|
||||||
.get("hud.press_key_to_toggle_keybindings_fmt")
|
.get("hud.press_key_to_toggle_keybindings_fmt")
|
||||||
.replace(
|
.replace("{key}", help_key.to_string().as_str()),
|
||||||
"{key}",
|
|
||||||
&format!("{:?}", global_state.settings.controls.help),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.down_from(self.ids.num_figures, 5.0)
|
.down_from(self.ids.num_figures, 5.0)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.set(self.ids.help_info, ui_widgets);
|
.set(self.ids.help_info, ui_widgets);
|
||||||
|
}
|
||||||
// Info about Debug Shortcut
|
// Info about Debug Shortcut
|
||||||
|
if let Some(toggle_debug_key) = global_state
|
||||||
|
.settings
|
||||||
|
.controls
|
||||||
|
.get_binding(GameInput::ToggleDebug)
|
||||||
|
{
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
.voxygen_i18n
|
.voxygen_i18n
|
||||||
.get("hud.press_key_to_toggle_debug_info_fmt")
|
.get("hud.press_key_to_toggle_debug_info_fmt")
|
||||||
.replace(
|
.replace("{key}", toggle_debug_key.to_string().as_str()),
|
||||||
"{key}",
|
|
||||||
&format!("{:?}", global_state.settings.controls.toggle_debug),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.down_from(self.ids.help_info, 5.0)
|
.down_from(self.ids.help_info, 5.0)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.set(self.ids.debug_info, ui_widgets);
|
.set(self.ids.debug_info, ui_widgets);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Help Window
|
// Help Window
|
||||||
|
if let Some(help_key) = global_state.settings.controls.get_binding(GameInput::Help) {
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
.voxygen_i18n
|
.voxygen_i18n
|
||||||
.get("hud.press_key_to_show_keybindings_fmt")
|
.get("hud.press_key_to_show_keybindings_fmt")
|
||||||
.replace(
|
.replace("{key}", help_key.to_string().as_str()),
|
||||||
"{key}",
|
|
||||||
&format!("{:?}", global_state.settings.controls.help),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.top_left_with_margins_on(ui_widgets.window, 5.0, 5.0)
|
.top_left_with_margins_on(ui_widgets.window, 5.0, 5.0)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(16))
|
.font_size(self.fonts.cyri.scale(16))
|
||||||
.set(self.ids.help_info, ui_widgets);
|
.set(self.ids.help_info, ui_widgets);
|
||||||
|
}
|
||||||
// Info about Debug Shortcut
|
// Info about Debug Shortcut
|
||||||
|
if let Some(toggle_debug_key) = global_state
|
||||||
|
.settings
|
||||||
|
.controls
|
||||||
|
.get_binding(GameInput::ToggleDebug)
|
||||||
|
{
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
.voxygen_i18n
|
.voxygen_i18n
|
||||||
.get("hud.press_key_to_show_debug_info_fmt")
|
.get("hud.press_key_to_show_debug_info_fmt")
|
||||||
.replace(
|
.replace("{key}", toggle_debug_key.to_string().as_str()),
|
||||||
"{key}",
|
|
||||||
&format!("{:?}", global_state.settings.controls.toggle_debug),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.down_from(self.ids.help_info, 5.0)
|
.down_from(self.ids.help_info, 5.0)
|
||||||
@ -1555,6 +1559,7 @@ impl Hud {
|
|||||||
.font_size(self.fonts.cyri.scale(12))
|
.font_size(self.fonts.cyri.scale(12))
|
||||||
.set(self.ids.debug_info, ui_widgets);
|
.set(self.ids.debug_info, ui_widgets);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Help Text
|
// Help Text
|
||||||
if self.show.help && !self.show.map && !self.show.esc_menu {
|
if self.show.help && !self.show.map && !self.show.esc_menu {
|
||||||
@ -1822,6 +1827,9 @@ impl Hud {
|
|||||||
settings_window::Event::AdjustWindowSize(new_size) => {
|
settings_window::Event::AdjustWindowSize(new_size) => {
|
||||||
events.push(Event::AdjustWindowSize(new_size));
|
events.push(Event::AdjustWindowSize(new_size));
|
||||||
},
|
},
|
||||||
|
settings_window::Event::ChangeBinding(game_input) => {
|
||||||
|
events.push(Event::ChangeBinding(game_input));
|
||||||
|
},
|
||||||
settings_window::Event::ChangeFreeLookBehavior(behavior) => {
|
settings_window::Event::ChangeFreeLookBehavior(behavior) => {
|
||||||
events.push(Event::ChangeFreeLookBehavior(behavior));
|
events.push(Event::ChangeFreeLookBehavior(behavior));
|
||||||
},
|
},
|
||||||
|
@ -6,12 +6,15 @@ use crate::{
|
|||||||
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
||||||
render::{AaMode, CloudMode, FluidMode},
|
render::{AaMode, CloudMode, FluidMode},
|
||||||
ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton},
|
ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton},
|
||||||
|
window::GameInput,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
|
position::Relative,
|
||||||
widget::{self, Button, DropDownList, Image, Rectangle, Scrollbar, Text},
|
widget::{self, Button, DropDownList, Image, Rectangle, Scrollbar, Text},
|
||||||
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||||
|
WidgetCommon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FPS_CHOICES: [u32; 11] = [15, 30, 40, 50, 60, 90, 120, 144, 240, 300, 500];
|
const FPS_CHOICES: [u32; 11] = [15, 30, 40, 50, 60, 90, 120, 144, 240, 300, 500];
|
||||||
@ -27,8 +30,9 @@ widget_ids! {
|
|||||||
settings_r,
|
settings_r,
|
||||||
settings_l,
|
settings_l,
|
||||||
settings_scrollbar,
|
settings_scrollbar,
|
||||||
controls_text,
|
controls_texts[],
|
||||||
controls_controls,
|
controls_buttons[],
|
||||||
|
controls_alignment_rectangle,
|
||||||
button_help,
|
button_help,
|
||||||
button_help2,
|
button_help2,
|
||||||
show_help_label,
|
show_help_label,
|
||||||
@ -221,6 +225,7 @@ pub enum Event {
|
|||||||
SctPlayerBatch(bool),
|
SctPlayerBatch(bool),
|
||||||
SctDamageBatch(bool),
|
SctDamageBatch(bool),
|
||||||
ChangeLanguage(LanguageMetadata),
|
ChangeLanguage(LanguageMetadata),
|
||||||
|
ChangeBinding(GameInput),
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
ChangeFreeLookBehavior(PressBehavior),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,142 +1333,86 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
// Contents
|
// Contents
|
||||||
if let SettingsTab::Controls = self.show.settings_tab {
|
if let SettingsTab::Controls = self.show.settings_tab {
|
||||||
let controls = &self.global_state.settings.controls;
|
let controls = &self.global_state.settings.controls;
|
||||||
Text::new(&self.localized_strings.get("hud.settings.control_names"))
|
if controls.keybindings.len() > state.ids.controls_texts.len()
|
||||||
|
|| controls.keybindings.len() > state.ids.controls_buttons.len()
|
||||||
|
{
|
||||||
|
state.update(|s| {
|
||||||
|
s.ids
|
||||||
|
.controls_texts
|
||||||
|
.resize(controls.keybindings.len(), &mut ui.widget_id_generator());
|
||||||
|
s.ids
|
||||||
|
.controls_buttons
|
||||||
|
.resize(controls.keybindings.len(), &mut ui.widget_id_generator());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Used for sequential placement in a flow-down pattern
|
||||||
|
let mut previous_text_id = None;
|
||||||
|
let mut keybindings_vec: Vec<&GameInput> = controls.keybindings.keys().collect();
|
||||||
|
keybindings_vec.sort();
|
||||||
|
// Loop all existing keybindings and the ids for text and button widgets
|
||||||
|
for (game_input, (&text_id, &button_id)) in keybindings_vec.into_iter().zip(
|
||||||
|
state
|
||||||
|
.ids
|
||||||
|
.controls_texts
|
||||||
|
.iter()
|
||||||
|
.zip(state.ids.controls_buttons.iter()),
|
||||||
|
) {
|
||||||
|
if let Some(key) = controls.get_binding(*game_input) {
|
||||||
|
let loc_key = self
|
||||||
|
.localized_strings
|
||||||
|
.get(game_input.get_localization_key());
|
||||||
|
let key_string = match self.global_state.window.remapping_keybindings {
|
||||||
|
Some(game_input_binding) => {
|
||||||
|
if *game_input == game_input_binding {
|
||||||
|
String::from(self.localized_strings.get("hud.settings.awaitingkey"))
|
||||||
|
} else {
|
||||||
|
key.to_string()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => key.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let text_widget = Text::new(loc_key)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.top_left_with_margins_on(state.ids.settings_content, 5.0, 5.0)
|
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(18))
|
.font_size(self.fonts.cyri.scale(18));
|
||||||
.set(state.ids.controls_text, ui);
|
let button_widget = Button::new()
|
||||||
// TODO: Replace with buttons that show actual keybinds and allow the user to
|
.label(&key_string)
|
||||||
// change them.
|
.label_color(TEXT_COLOR)
|
||||||
#[rustfmt::skip]
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
Text::new(&format!(
|
.label_font_size(self.fonts.cyri.scale(15))
|
||||||
"{}\n\
|
.w(150.0)
|
||||||
{}\n\
|
.rgba(0.0, 0.0, 0.0, 0.0)
|
||||||
{}\n\
|
.border_rgba(0.0, 0.0, 0.0, 255.0)
|
||||||
{}\n\
|
.label_y(Relative::Scalar(3.0));
|
||||||
{}\n\
|
// Place top-left if it's the first text, else under the previous one
|
||||||
{}\n\
|
let text_widget = match previous_text_id {
|
||||||
{}\n\
|
None => text_widget.top_left_with_margins_on(
|
||||||
\n\
|
state.ids.settings_content,
|
||||||
\n\
|
10.0,
|
||||||
{}\n\
|
5.0,
|
||||||
{}\n\
|
),
|
||||||
{}\n\
|
Some(prev_id) => text_widget.down_from(prev_id, 10.0),
|
||||||
{}\n\
|
};
|
||||||
\n\
|
let text_width = text_widget.get_w(ui).unwrap_or(0.0);
|
||||||
{}\n\
|
text_widget.set(text_id, ui);
|
||||||
\n\
|
if button_widget
|
||||||
{}\n\
|
.right_from(text_id, 350.0 - text_width)
|
||||||
\n\
|
.set(button_id, ui)
|
||||||
{}\n\
|
.was_clicked()
|
||||||
\n\
|
{
|
||||||
{}\n\
|
events.push(Event::ChangeBinding(*game_input));
|
||||||
\n\
|
}
|
||||||
{}\n\
|
// Set the previous id to the current one for the next cycle
|
||||||
\n\
|
previous_text_id = Some(text_id);
|
||||||
{}\n\
|
}
|
||||||
\n\
|
}
|
||||||
{}\n\
|
// Add an empty text widget to simulate some bottom margin, because conrod sucks
|
||||||
\n\
|
if let Some(prev_id) = previous_text_id {
|
||||||
{}\n\
|
Rectangle::fill_with([1.0, 1.0], color::TRANSPARENT)
|
||||||
\n\
|
.down_from(prev_id, 10.0)
|
||||||
{}\n\
|
.set(state.ids.controls_alignment_rectangle, ui);
|
||||||
\n\
|
}
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
{}\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
\n\
|
|
||||||
",
|
|
||||||
controls.toggle_cursor,
|
|
||||||
controls.help,
|
|
||||||
controls.toggle_interface,
|
|
||||||
controls.toggle_debug,
|
|
||||||
controls.screenshot,
|
|
||||||
controls.toggle_ingame_ui,
|
|
||||||
controls.fullscreen,
|
|
||||||
controls.move_forward,
|
|
||||||
controls.move_left,
|
|
||||||
controls.move_back,
|
|
||||||
controls.move_right,
|
|
||||||
controls.jump,
|
|
||||||
controls.glide,
|
|
||||||
"??", // Dodge
|
|
||||||
controls.roll,
|
|
||||||
controls.climb,
|
|
||||||
controls.climb_down,
|
|
||||||
"??", // Auto Walk
|
|
||||||
controls.toggle_wield,
|
|
||||||
"??", // Put on/Remove Helmet
|
|
||||||
controls.sit,
|
|
||||||
controls.mount,
|
|
||||||
controls.interact,
|
|
||||||
controls.primary,
|
|
||||||
controls.secondary,
|
|
||||||
"1", // Skillbar Slot 1
|
|
||||||
"2", // Skillbar Slot 2
|
|
||||||
"3", // Skillbar Slot 3
|
|
||||||
"4", // Skillbar Slot 4
|
|
||||||
"5", // Skillbar Slot 5
|
|
||||||
"6", // Skillbar Slot 6
|
|
||||||
"7", // Skillbar Slot 7
|
|
||||||
"8", // Skillbar Slot 8
|
|
||||||
"9", // Skillbar Slot 9
|
|
||||||
"0", // Skillbar Slot 10
|
|
||||||
controls.escape,
|
|
||||||
controls.settings,
|
|
||||||
controls.social,
|
|
||||||
controls.map,
|
|
||||||
controls.spellbook,
|
|
||||||
//controls.character_window,
|
|
||||||
//controls.quest_log,
|
|
||||||
controls.bag,
|
|
||||||
controls.enter,
|
|
||||||
"Mouse Wheel", // Scroll chat
|
|
||||||
controls.free_look
|
|
||||||
))
|
|
||||||
.color(TEXT_COLOR)
|
|
||||||
.right_from(state.ids.controls_text, 0.0)
|
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
|
||||||
.font_size(self.fonts.cyri.scale(18))
|
|
||||||
.set(state.ids.controls_controls, ui);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4) Video Tab -----------------------------------
|
// 4) Video Tab -----------------------------------
|
||||||
|
@ -5,6 +5,7 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
i18n::{i18n_asset_key, VoxygenLocalization},
|
i18n::{i18n_asset_key, VoxygenLocalization},
|
||||||
ui::fonts::ConrodVoxygenFonts,
|
ui::fonts::ConrodVoxygenFonts,
|
||||||
|
window::GameInput,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -300,16 +301,23 @@ impl<'a> Widget for Skillbar<'a> {
|
|||||||
.set(state.ids.level_down, ui);
|
.set(state.ids.level_down, ui);
|
||||||
// Death message
|
// Death message
|
||||||
if self.stats.is_dead {
|
if self.stats.is_dead {
|
||||||
|
if let Some(key) = self
|
||||||
|
.global_state
|
||||||
|
.settings
|
||||||
|
.controls
|
||||||
|
.get_binding(GameInput::Respawn)
|
||||||
|
{
|
||||||
Text::new(&localized_strings.get("hud.you_died"))
|
Text::new(&localized_strings.get("hud.you_died"))
|
||||||
.middle_of(ui.window)
|
.middle_of(ui.window)
|
||||||
.font_size(self.fonts.cyri.scale(50))
|
.font_size(self.fonts.cyri.scale(50))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(Color::Rgba(0.0, 0.0, 0.0, 1.0))
|
.color(Color::Rgba(0.0, 0.0, 0.0, 1.0))
|
||||||
.set(state.ids.death_message_1_bg, ui);
|
.set(state.ids.death_message_1_bg, ui);
|
||||||
Text::new(&localized_strings.get("hud.press_key_to_respawn").replace(
|
Text::new(
|
||||||
"{key}",
|
&localized_strings
|
||||||
&format!("{:?}", self.global_state.settings.controls.respawn),
|
.get("hud.press_key_to_respawn")
|
||||||
))
|
.replace("{key}", key.to_string().as_str()),
|
||||||
|
)
|
||||||
.mid_bottom_with_margin_on(state.ids.death_message_1_bg, -120.0)
|
.mid_bottom_with_margin_on(state.ids.death_message_1_bg, -120.0)
|
||||||
.font_size(self.fonts.cyri.scale(30))
|
.font_size(self.fonts.cyri.scale(30))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
@ -321,16 +329,18 @@ impl<'a> Widget for Skillbar<'a> {
|
|||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(CRITICAL_HP_COLOR)
|
.color(CRITICAL_HP_COLOR)
|
||||||
.set(state.ids.death_message_1, ui);
|
.set(state.ids.death_message_1, ui);
|
||||||
Text::new(&localized_strings.get("hud.press_key_to_respawn").replace(
|
Text::new(
|
||||||
"{key}",
|
&localized_strings
|
||||||
&format!("{:?}", self.global_state.settings.controls.respawn),
|
.get("hud.press_key_to_respawn")
|
||||||
))
|
.replace("{key}", key.to_string().as_str()),
|
||||||
|
)
|
||||||
.bottom_left_with_margins_on(state.ids.death_message_2_bg, 2.0, 2.0)
|
.bottom_left_with_margins_on(state.ids.death_message_2_bg, 2.0, 2.0)
|
||||||
.font_size(self.fonts.cyri.scale(30))
|
.font_size(self.fonts.cyri.scale(30))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(CRITICAL_HP_COLOR)
|
.color(CRITICAL_HP_COLOR)
|
||||||
.set(state.ids.death_message_2, ui);
|
.set(state.ids.death_message_2, ui);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Experience-Bar
|
// Experience-Bar
|
||||||
match self.global_state.settings.gameplay.xp_bar {
|
match self.global_state.settings.gameplay.xp_bar {
|
||||||
XpBar::Always => {
|
XpBar::Always => {
|
||||||
|
@ -713,6 +713,9 @@ impl PlayState for SessionState {
|
|||||||
global_state.settings.graphics.window_size = new_size;
|
global_state.settings.graphics.window_size = new_size;
|
||||||
global_state.settings.save_to_file_warn();
|
global_state.settings.save_to_file_warn();
|
||||||
},
|
},
|
||||||
|
HudEvent::ChangeBinding(game_input) => {
|
||||||
|
global_state.window.set_keybinding_mode(game_input);
|
||||||
|
},
|
||||||
HudEvent::ChangeFreeLookBehavior(behavior) => {
|
HudEvent::ChangeFreeLookBehavior(behavior) => {
|
||||||
global_state.settings.gameplay.free_look_behavior = behavior;
|
global_state.settings.gameplay.free_look_behavior = behavior;
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,7 @@ use crate::{
|
|||||||
i18n,
|
i18n,
|
||||||
render::{AaMode, CloudMode, FluidMode},
|
render::{AaMode, CloudMode, FluidMode},
|
||||||
ui::ScaleMode,
|
ui::ScaleMode,
|
||||||
window::KeyMouse,
|
window::{GameInput, KeyMouse},
|
||||||
};
|
};
|
||||||
use directories::{ProjectDirs, UserDirs};
|
use directories::{ProjectDirs, UserDirs};
|
||||||
use glutin::{MouseButton, VirtualKeyCode};
|
use glutin::{MouseButton, VirtualKeyCode};
|
||||||
@ -12,46 +12,47 @@ use log::warn;
|
|||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::{fs, io::prelude::*, path::PathBuf};
|
use std::{fs, io::prelude::*, path::PathBuf};
|
||||||
|
|
||||||
|
// ControlSetting-like struct used by Serde, to handle not serializing/building
|
||||||
|
// post-deserializing the inverse_keybindings hashmap
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct ControlSettingsSerde {
|
||||||
|
keybindings: HashMap<GameInput, KeyMouse>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlSettings> for ControlSettingsSerde {
|
||||||
|
fn from(control_settings: ControlSettings) -> Self {
|
||||||
|
let mut user_bindings: HashMap<GameInput, KeyMouse> = HashMap::new();
|
||||||
|
// Do a delta between default() ControlSettings and the argument, and let
|
||||||
|
// keybindings be only the custom keybindings chosen by the user.
|
||||||
|
for (k, v) in control_settings.keybindings {
|
||||||
|
if ControlSettings::default_binding(k) != v {
|
||||||
|
// Keybinding chosen by the user
|
||||||
|
user_bindings.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlSettingsSerde {
|
||||||
|
keybindings: user_bindings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `ControlSettings` contains keybindings.
|
/// `ControlSettings` contains keybindings.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(from = "ControlSettingsSerde", into = "ControlSettingsSerde")]
|
||||||
pub struct ControlSettings {
|
pub struct ControlSettings {
|
||||||
pub primary: KeyMouse,
|
pub keybindings: HashMap<GameInput, KeyMouse>,
|
||||||
pub secondary: KeyMouse,
|
pub inverse_keybindings: HashMap<KeyMouse, HashSet<GameInput>>, // used in event loop
|
||||||
pub ability3: KeyMouse,
|
}
|
||||||
pub toggle_cursor: KeyMouse,
|
|
||||||
pub escape: KeyMouse,
|
impl From<ControlSettingsSerde> for ControlSettings {
|
||||||
pub enter: KeyMouse,
|
fn from(control_serde: ControlSettingsSerde) -> Self {
|
||||||
pub command: KeyMouse,
|
let user_keybindings = control_serde.keybindings;
|
||||||
pub move_forward: KeyMouse,
|
let mut control_settings = ControlSettings::default();
|
||||||
pub move_left: KeyMouse,
|
for (k, v) in user_keybindings {
|
||||||
pub move_back: KeyMouse,
|
control_settings.modify_binding(k, v);
|
||||||
pub move_right: KeyMouse,
|
}
|
||||||
pub jump: KeyMouse,
|
control_settings
|
||||||
pub sit: KeyMouse,
|
}
|
||||||
pub glide: KeyMouse,
|
|
||||||
pub climb: KeyMouse,
|
|
||||||
pub climb_down: KeyMouse,
|
|
||||||
pub wall_leap: KeyMouse,
|
|
||||||
pub mount: KeyMouse,
|
|
||||||
pub map: KeyMouse,
|
|
||||||
pub bag: KeyMouse,
|
|
||||||
pub social: KeyMouse,
|
|
||||||
pub spellbook: KeyMouse,
|
|
||||||
pub settings: KeyMouse,
|
|
||||||
pub help: KeyMouse,
|
|
||||||
pub toggle_interface: KeyMouse,
|
|
||||||
pub toggle_debug: KeyMouse,
|
|
||||||
pub fullscreen: KeyMouse,
|
|
||||||
pub screenshot: KeyMouse,
|
|
||||||
pub toggle_ingame_ui: KeyMouse,
|
|
||||||
pub roll: KeyMouse,
|
|
||||||
pub respawn: KeyMouse,
|
|
||||||
pub interact: KeyMouse,
|
|
||||||
pub toggle_wield: KeyMouse,
|
|
||||||
pub swap_loadout: KeyMouse,
|
|
||||||
pub charge: KeyMouse,
|
|
||||||
pub free_look: KeyMouse,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Since Macbook trackpads lack middle click, on OS X we default to LShift
|
/// Since Macbook trackpads lack middle click, on OS X we default to LShift
|
||||||
@ -64,46 +65,135 @@ const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Key(VirtualKeyCode::LShift);
|
|||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
|
const MIDDLE_CLICK_KEY: KeyMouse = KeyMouse::Mouse(MouseButton::Middle);
|
||||||
|
|
||||||
|
impl ControlSettings {
|
||||||
|
pub fn get_binding(&self, game_input: GameInput) -> Option<KeyMouse> {
|
||||||
|
self.keybindings.get(&game_input).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_associated_game_inputs(&self, key_mouse: &KeyMouse) -> Option<&HashSet<GameInput>> {
|
||||||
|
self.inverse_keybindings.get(key_mouse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||||
|
self.keybindings.insert(game_input, key_mouse);
|
||||||
|
self.inverse_keybindings
|
||||||
|
.entry(key_mouse)
|
||||||
|
.or_default()
|
||||||
|
.insert(game_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn modify_binding(&mut self, game_input: GameInput, key_mouse: KeyMouse) {
|
||||||
|
// For the KeyMouse->GameInput hashmap, we first need to remove the GameInput
|
||||||
|
// from the old binding
|
||||||
|
if let Some(old_binding) = self.get_binding(game_input) {
|
||||||
|
self.inverse_keybindings
|
||||||
|
.entry(old_binding)
|
||||||
|
.or_default()
|
||||||
|
.remove(&game_input);
|
||||||
|
}
|
||||||
|
// then we add the GameInput to the proper key
|
||||||
|
self.inverse_keybindings
|
||||||
|
.entry(key_mouse)
|
||||||
|
.or_default()
|
||||||
|
.insert(game_input);
|
||||||
|
// For the GameInput->KeyMouse hashmap, just overwrite the value
|
||||||
|
self.keybindings.insert(game_input, key_mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
||||||
|
// If a new GameInput is added, be sure to update ControlSettings::default()
|
||||||
|
// too!
|
||||||
|
match game_input {
|
||||||
|
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
||||||
|
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
||||||
|
GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Tab),
|
||||||
|
GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape),
|
||||||
|
GameInput::Enter => KeyMouse::Key(VirtualKeyCode::Return),
|
||||||
|
GameInput::Command => KeyMouse::Key(VirtualKeyCode::Slash),
|
||||||
|
GameInput::MoveForward => KeyMouse::Key(VirtualKeyCode::W),
|
||||||
|
GameInput::MoveLeft => KeyMouse::Key(VirtualKeyCode::A),
|
||||||
|
GameInput::MoveBack => KeyMouse::Key(VirtualKeyCode::S),
|
||||||
|
GameInput::MoveRight => KeyMouse::Key(VirtualKeyCode::D),
|
||||||
|
GameInput::Jump => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::Sit => KeyMouse::Key(VirtualKeyCode::K),
|
||||||
|
GameInput::Glide => KeyMouse::Key(VirtualKeyCode::LShift),
|
||||||
|
GameInput::Climb => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::ClimbDown => KeyMouse::Key(VirtualKeyCode::LControl),
|
||||||
|
GameInput::WallLeap => MIDDLE_CLICK_KEY,
|
||||||
|
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
|
||||||
|
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
|
||||||
|
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
|
||||||
|
GameInput::Social => KeyMouse::Key(VirtualKeyCode::O),
|
||||||
|
GameInput::Spellbook => KeyMouse::Key(VirtualKeyCode::P),
|
||||||
|
GameInput::Settings => KeyMouse::Key(VirtualKeyCode::N),
|
||||||
|
GameInput::Help => KeyMouse::Key(VirtualKeyCode::F1),
|
||||||
|
GameInput::ToggleInterface => KeyMouse::Key(VirtualKeyCode::F2),
|
||||||
|
GameInput::ToggleDebug => KeyMouse::Key(VirtualKeyCode::F3),
|
||||||
|
GameInput::Fullscreen => KeyMouse::Key(VirtualKeyCode::F11),
|
||||||
|
GameInput::Screenshot => KeyMouse::Key(VirtualKeyCode::F4),
|
||||||
|
GameInput::ToggleIngameUi => KeyMouse::Key(VirtualKeyCode::F6),
|
||||||
|
GameInput::Roll => MIDDLE_CLICK_KEY,
|
||||||
|
GameInput::Respawn => KeyMouse::Key(VirtualKeyCode::Space),
|
||||||
|
GameInput::Interact => KeyMouse::Mouse(MouseButton::Right),
|
||||||
|
GameInput::ToggleWield => KeyMouse::Key(VirtualKeyCode::T),
|
||||||
|
GameInput::Charge => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||||
|
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
||||||
|
GameInput::Ability3 => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||||
|
GameInput::SwapLoadout => KeyMouse::Key(VirtualKeyCode::LAlt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Default for ControlSettings {
|
impl Default for ControlSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
let mut new_settings = Self {
|
||||||
primary: KeyMouse::Mouse(MouseButton::Left),
|
keybindings: HashMap::new(),
|
||||||
secondary: KeyMouse::Mouse(MouseButton::Right),
|
inverse_keybindings: HashMap::new(),
|
||||||
ability3: KeyMouse::Key(VirtualKeyCode::Key1),
|
};
|
||||||
toggle_cursor: KeyMouse::Key(VirtualKeyCode::Tab),
|
// Sets the initial keybindings for those GameInputs. If a new one is created in
|
||||||
escape: KeyMouse::Key(VirtualKeyCode::Escape),
|
// future, you'll have to update default_binding, and you should update this vec
|
||||||
enter: KeyMouse::Key(VirtualKeyCode::Return),
|
// too.
|
||||||
command: KeyMouse::Key(VirtualKeyCode::Slash),
|
let game_inputs = vec![
|
||||||
move_forward: KeyMouse::Key(VirtualKeyCode::W),
|
GameInput::Primary,
|
||||||
move_left: KeyMouse::Key(VirtualKeyCode::A),
|
GameInput::Secondary,
|
||||||
move_back: KeyMouse::Key(VirtualKeyCode::S),
|
GameInput::ToggleCursor,
|
||||||
move_right: KeyMouse::Key(VirtualKeyCode::D),
|
GameInput::MoveForward,
|
||||||
jump: KeyMouse::Key(VirtualKeyCode::Space),
|
GameInput::MoveBack,
|
||||||
sit: KeyMouse::Key(VirtualKeyCode::K),
|
GameInput::MoveLeft,
|
||||||
glide: KeyMouse::Key(VirtualKeyCode::LShift),
|
GameInput::MoveRight,
|
||||||
climb: KeyMouse::Key(VirtualKeyCode::Space),
|
GameInput::Jump,
|
||||||
climb_down: KeyMouse::Key(VirtualKeyCode::LControl),
|
GameInput::Sit,
|
||||||
wall_leap: MIDDLE_CLICK_KEY,
|
GameInput::Glide,
|
||||||
mount: KeyMouse::Key(VirtualKeyCode::F),
|
GameInput::Climb,
|
||||||
map: KeyMouse::Key(VirtualKeyCode::M),
|
GameInput::ClimbDown,
|
||||||
bag: KeyMouse::Key(VirtualKeyCode::B),
|
GameInput::WallLeap,
|
||||||
social: KeyMouse::Key(VirtualKeyCode::O),
|
GameInput::Mount,
|
||||||
spellbook: KeyMouse::Key(VirtualKeyCode::P),
|
GameInput::Enter,
|
||||||
settings: KeyMouse::Key(VirtualKeyCode::N),
|
GameInput::Command,
|
||||||
help: KeyMouse::Key(VirtualKeyCode::F1),
|
GameInput::Escape,
|
||||||
toggle_interface: KeyMouse::Key(VirtualKeyCode::F2),
|
GameInput::Map,
|
||||||
toggle_debug: KeyMouse::Key(VirtualKeyCode::F3),
|
GameInput::Bag,
|
||||||
fullscreen: KeyMouse::Key(VirtualKeyCode::F11),
|
GameInput::Social,
|
||||||
screenshot: KeyMouse::Key(VirtualKeyCode::F4),
|
GameInput::Spellbook,
|
||||||
toggle_ingame_ui: KeyMouse::Key(VirtualKeyCode::F6),
|
GameInput::Settings,
|
||||||
roll: MIDDLE_CLICK_KEY,
|
GameInput::ToggleInterface,
|
||||||
respawn: KeyMouse::Key(VirtualKeyCode::Space),
|
GameInput::Help,
|
||||||
interact: KeyMouse::Mouse(MouseButton::Right),
|
GameInput::ToggleDebug,
|
||||||
toggle_wield: KeyMouse::Key(VirtualKeyCode::T),
|
GameInput::Fullscreen,
|
||||||
swap_loadout: KeyMouse::Key(VirtualKeyCode::Q),
|
GameInput::Screenshot,
|
||||||
charge: KeyMouse::Key(VirtualKeyCode::Key1),
|
GameInput::ToggleIngameUi,
|
||||||
free_look: KeyMouse::Key(VirtualKeyCode::L),
|
GameInput::Roll,
|
||||||
|
GameInput::Respawn,
|
||||||
|
GameInput::Interact,
|
||||||
|
GameInput::ToggleWield,
|
||||||
|
GameInput::Charge,
|
||||||
|
GameInput::FreeLook,
|
||||||
|
GameInput::Ability3,
|
||||||
|
GameInput::SwapLoadout,
|
||||||
|
];
|
||||||
|
for game_input in game_inputs {
|
||||||
|
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
||||||
}
|
}
|
||||||
|
new_settings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
controller::*,
|
controller::*,
|
||||||
render::{Renderer, WinColorFmt, WinDepthFmt},
|
render::{Renderer, WinColorFmt, WinDepthFmt},
|
||||||
settings::Settings,
|
settings::{ControlSettings, Settings},
|
||||||
ui, Error,
|
ui, Error,
|
||||||
};
|
};
|
||||||
use gilrs::{EventType, Gilrs};
|
use gilrs::{EventType, Gilrs};
|
||||||
@ -12,7 +12,7 @@ use std::fmt;
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// Represents a key that the game recognises after input mapping.
|
/// Represents a key that the game recognises after input mapping.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
||||||
pub enum GameInput {
|
pub enum GameInput {
|
||||||
Primary,
|
Primary,
|
||||||
Secondary,
|
Secondary,
|
||||||
@ -34,8 +34,6 @@ pub enum GameInput {
|
|||||||
Escape,
|
Escape,
|
||||||
Map,
|
Map,
|
||||||
Bag,
|
Bag,
|
||||||
QuestLog,
|
|
||||||
CharacterWindow,
|
|
||||||
Social,
|
Social,
|
||||||
Spellbook,
|
Spellbook,
|
||||||
Settings,
|
Settings,
|
||||||
@ -54,6 +52,49 @@ pub enum GameInput {
|
|||||||
FreeLook,
|
FreeLook,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GameInput {
|
||||||
|
pub fn get_localization_key(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
GameInput::Primary => "gameinput.primary",
|
||||||
|
GameInput::Secondary => "gameinput.secondary",
|
||||||
|
GameInput::ToggleCursor => "gameinput.togglecursor",
|
||||||
|
GameInput::MoveForward => "gameinput.moveforward",
|
||||||
|
GameInput::MoveLeft => "gameinput.moveleft",
|
||||||
|
GameInput::MoveRight => "gameinput.moveright",
|
||||||
|
GameInput::MoveBack => "gameinput.moveback",
|
||||||
|
GameInput::Jump => "gameinput.jump",
|
||||||
|
GameInput::Sit => "gameinput.sit",
|
||||||
|
GameInput::Glide => "gameinput.glide",
|
||||||
|
GameInput::Climb => "gameinput.climb",
|
||||||
|
GameInput::ClimbDown => "gameinput.climbdown",
|
||||||
|
GameInput::WallLeap => "gameinput.wallleap",
|
||||||
|
GameInput::Mount => "gameinput.mount",
|
||||||
|
GameInput::Enter => "gameinput.enter",
|
||||||
|
GameInput::Command => "gameinput.command",
|
||||||
|
GameInput::Escape => "gameinput.escape",
|
||||||
|
GameInput::Map => "gameinput.map",
|
||||||
|
GameInput::Bag => "gameinput.bag",
|
||||||
|
GameInput::Social => "gameinput.social",
|
||||||
|
GameInput::Spellbook => "gameinput.spellbook",
|
||||||
|
GameInput::Settings => "gameinput.settings",
|
||||||
|
GameInput::ToggleInterface => "gameinput.toggleinterface",
|
||||||
|
GameInput::Help => "gameinput.help",
|
||||||
|
GameInput::ToggleDebug => "gameinput.toggledebug",
|
||||||
|
GameInput::Fullscreen => "gameinput.fullscreen",
|
||||||
|
GameInput::Screenshot => "gameinput.screenshot",
|
||||||
|
GameInput::ToggleIngameUi => "gameinput.toggleingameui",
|
||||||
|
GameInput::Roll => "gameinput.roll",
|
||||||
|
GameInput::Respawn => "gameinput.respawn",
|
||||||
|
GameInput::Interact => "gameinput.interact",
|
||||||
|
GameInput::ToggleWield => "gameinput.togglewield",
|
||||||
|
GameInput::Charge => "gameinput.charge",
|
||||||
|
GameInput::FreeLook => "gameinput.freelook",
|
||||||
|
GameInput::Ability3 => "gameinput.ability3",
|
||||||
|
GameInput::SwapLoadout => "gameinput.swaploadout",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a key that the game menus recognise after input mapping
|
/// Represents a key that the game menus recognise after input mapping
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub enum MenuInput {
|
pub enum MenuInput {
|
||||||
@ -319,8 +360,8 @@ pub struct Window {
|
|||||||
pub mouse_y_inversion: bool,
|
pub mouse_y_inversion: bool,
|
||||||
fullscreen: bool,
|
fullscreen: bool,
|
||||||
needs_refresh_resize: bool,
|
needs_refresh_resize: bool,
|
||||||
key_map: HashMap<KeyMouse, Vec<GameInput>>,
|
|
||||||
keypress_map: HashMap<GameInput, glutin::ElementState>,
|
keypress_map: HashMap<GameInput, glutin::ElementState>,
|
||||||
|
pub remapping_keybindings: Option<GameInput>,
|
||||||
supplement_events: Vec<Event>,
|
supplement_events: Vec<Event>,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
gilrs: Option<Gilrs>,
|
gilrs: Option<Gilrs>,
|
||||||
@ -355,116 +396,6 @@ impl Window {
|
|||||||
)
|
)
|
||||||
.map_err(|err| Error::BackendError(Box::new(err)))?;
|
.map_err(|err| Error::BackendError(Box::new(err)))?;
|
||||||
|
|
||||||
let mut map: HashMap<_, Vec<_>> = HashMap::new();
|
|
||||||
map.entry(settings.controls.primary)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Primary);
|
|
||||||
map.entry(settings.controls.secondary)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Secondary);
|
|
||||||
map.entry(settings.controls.ability3)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Ability3);
|
|
||||||
map.entry(settings.controls.toggle_cursor)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::ToggleCursor);
|
|
||||||
map.entry(settings.controls.escape)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Escape);
|
|
||||||
map.entry(settings.controls.enter)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Enter);
|
|
||||||
map.entry(settings.controls.command)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Command);
|
|
||||||
map.entry(settings.controls.move_forward)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::MoveForward);
|
|
||||||
map.entry(settings.controls.move_left)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::MoveLeft);
|
|
||||||
map.entry(settings.controls.move_back)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::MoveBack);
|
|
||||||
map.entry(settings.controls.move_right)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::MoveRight);
|
|
||||||
map.entry(settings.controls.jump)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Jump);
|
|
||||||
map.entry(settings.controls.sit)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Sit);
|
|
||||||
map.entry(settings.controls.glide)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Glide);
|
|
||||||
map.entry(settings.controls.climb)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Climb);
|
|
||||||
map.entry(settings.controls.climb_down)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::ClimbDown);
|
|
||||||
map.entry(settings.controls.wall_leap)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::WallLeap);
|
|
||||||
map.entry(settings.controls.mount)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Mount);
|
|
||||||
map.entry(settings.controls.map)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Map);
|
|
||||||
map.entry(settings.controls.bag)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Bag);
|
|
||||||
map.entry(settings.controls.social)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Social);
|
|
||||||
map.entry(settings.controls.spellbook)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Spellbook);
|
|
||||||
map.entry(settings.controls.settings)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Settings);
|
|
||||||
map.entry(settings.controls.help)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Help);
|
|
||||||
map.entry(settings.controls.toggle_interface)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::ToggleInterface);
|
|
||||||
map.entry(settings.controls.toggle_debug)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::ToggleDebug);
|
|
||||||
map.entry(settings.controls.fullscreen)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Fullscreen);
|
|
||||||
map.entry(settings.controls.screenshot)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Screenshot);
|
|
||||||
map.entry(settings.controls.toggle_ingame_ui)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::ToggleIngameUi);
|
|
||||||
map.entry(settings.controls.roll)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Roll);
|
|
||||||
map.entry(settings.controls.respawn)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Respawn);
|
|
||||||
map.entry(settings.controls.interact)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Interact);
|
|
||||||
map.entry(settings.controls.toggle_wield)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::ToggleWield);
|
|
||||||
map.entry(settings.controls.swap_loadout)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::SwapLoadout);
|
|
||||||
map.entry(settings.controls.charge)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::Charge);
|
|
||||||
map.entry(settings.controls.free_look)
|
|
||||||
.or_default()
|
|
||||||
.push(GameInput::FreeLook);
|
|
||||||
|
|
||||||
let keypress_map = HashMap::new();
|
let keypress_map = HashMap::new();
|
||||||
|
|
||||||
let gilrs = match Gilrs::new() {
|
let gilrs = match Gilrs::new() {
|
||||||
@ -510,8 +441,8 @@ impl Window {
|
|||||||
mouse_y_inversion: settings.gameplay.mouse_y_inversion,
|
mouse_y_inversion: settings.gameplay.mouse_y_inversion,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
needs_refresh_resize: false,
|
needs_refresh_resize: false,
|
||||||
key_map: map,
|
|
||||||
keypress_map,
|
keypress_map,
|
||||||
|
remapping_keybindings: None,
|
||||||
supplement_events: vec![],
|
supplement_events: vec![],
|
||||||
focused: true,
|
focused: true,
|
||||||
gilrs,
|
gilrs,
|
||||||
@ -543,8 +474,9 @@ impl Window {
|
|||||||
let cursor_grabbed = self.cursor_grabbed;
|
let cursor_grabbed = self.cursor_grabbed;
|
||||||
let renderer = &mut self.renderer;
|
let renderer = &mut self.renderer;
|
||||||
let window = &mut self.window;
|
let window = &mut self.window;
|
||||||
|
let remapping_keybindings = &mut self.remapping_keybindings;
|
||||||
let focused = &mut self.focused;
|
let focused = &mut self.focused;
|
||||||
let key_map = &self.key_map;
|
let controls = &mut settings.controls;
|
||||||
let keypress_map = &mut self.keypress_map;
|
let keypress_map = &mut self.keypress_map;
|
||||||
let pan_sensitivity = self.pan_sensitivity;
|
let pan_sensitivity = self.pan_sensitivity;
|
||||||
let zoom_sensitivity = self.zoom_sensitivity;
|
let zoom_sensitivity = self.zoom_sensitivity;
|
||||||
@ -577,23 +509,27 @@ impl Window {
|
|||||||
},
|
},
|
||||||
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
||||||
glutin::WindowEvent::MouseInput { button, state, .. } => {
|
glutin::WindowEvent::MouseInput { button, state, .. } => {
|
||||||
if let (true, Some(game_inputs)) =
|
if let Some(game_inputs) = Window::map_input(
|
||||||
(cursor_grabbed, key_map.get(&KeyMouse::Mouse(button)))
|
KeyMouse::Mouse(button),
|
||||||
{
|
controls,
|
||||||
|
remapping_keybindings,
|
||||||
|
) {
|
||||||
for game_input in game_inputs {
|
for game_input in game_inputs {
|
||||||
events.push(Event::InputUpdate(
|
events.push(Event::InputUpdate(
|
||||||
*game_input,
|
*game_input,
|
||||||
state == glutin::ElementState::Pressed,
|
state == glutin::ElementState::Pressed,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
events.push(Event::MouseButton(button, state));
|
events.push(Event::MouseButton(button, state));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode
|
glutin::WindowEvent::KeyboardInput { input, .. } => {
|
||||||
{
|
if let Some(key) = input.virtual_keycode {
|
||||||
Some(key) => {
|
if let Some(game_inputs) = Window::map_input(
|
||||||
let game_inputs = key_map.get(&KeyMouse::Key(key));
|
KeyMouse::Key(key),
|
||||||
if let Some(game_inputs) = game_inputs {
|
controls,
|
||||||
|
remapping_keybindings,
|
||||||
|
) {
|
||||||
for game_input in game_inputs {
|
for game_input in game_inputs {
|
||||||
match game_input {
|
match game_input {
|
||||||
GameInput::Fullscreen => {
|
GameInput::Fullscreen => {
|
||||||
@ -631,9 +567,9 @@ impl Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
|
||||||
},
|
|
||||||
glutin::WindowEvent::Focused(state) => {
|
glutin::WindowEvent::Focused(state) => {
|
||||||
*focused = state;
|
*focused = state;
|
||||||
events.push(Event::Focused(state));
|
events.push(Event::Focused(state));
|
||||||
@ -1000,4 +936,33 @@ impl Window {
|
|||||||
) {
|
) {
|
||||||
map.insert(input, state);
|
map.insert(input, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function used to handle Mouse and Key events. It first checks if we're in
|
||||||
|
// remapping mode for a specific GameInput. If we are, we modify the binding
|
||||||
|
// of that GameInput with the KeyMouse passed. Else, we return an iterator of
|
||||||
|
// the GameInputs for that KeyMouse.
|
||||||
|
fn map_input<'a>(
|
||||||
|
key_mouse: KeyMouse,
|
||||||
|
controls: &'a mut ControlSettings,
|
||||||
|
remapping: &mut Option<GameInput>,
|
||||||
|
) -> Option<impl Iterator<Item = &'a GameInput>> {
|
||||||
|
match *remapping {
|
||||||
|
Some(game_input) => {
|
||||||
|
controls.modify_binding(game_input, key_mouse);
|
||||||
|
*remapping = None;
|
||||||
|
None
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
if let Some(game_inputs) = controls.get_associated_game_inputs(&key_mouse) {
|
||||||
|
Some(game_inputs.iter())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_keybinding_mode(&mut self, game_input: GameInput) {
|
||||||
|
self.remapping_keybindings = Some(game_input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user