diff --git a/CHANGELOG.md b/CHANGELOG.md index f22f4984d3..2068ba23c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bag tooltips only show slots now - Removed infinite armour values from most admin items - Item tooltips during trades will now inform the user of what ctrl-click and shift-click do +- International keyboards can now display more key names on Linux and Windows instead of `Unknown`. ### Removed diff --git a/Cargo.lock b/Cargo.lock index 0da63ea0dd..29b5d10f37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2570,6 +2570,19 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "keyboard-keynames" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6dbe132877d7a0327c4282840703c2cb456312fae930898b5dc126844889626" +dependencies = [ + "wayland-client 0.28.5", + "winapi 0.3.9", + "winit", + "xcb 0.8.2", + "xkbcommon", +] + [[package]] name = "khronos_api" version = "3.1.0" @@ -2820,6 +2833,16 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "memmap2" version = "0.1.0" @@ -5687,6 +5710,7 @@ dependencies = [ "image", "inline_tweak", "itertools 0.10.0", + "keyboard-keynames", "lazy_static", "native-dialog", "num 0.4.0", @@ -6435,7 +6459,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5e937afd03b64b7be4f959cc044e09260a47241b71e56933f37db097bf7859d" dependencies = [ - "xcb", + "xcb 0.9.0", ] [[package]] @@ -6471,6 +6495,16 @@ dependencies = [ "libc", ] +[[package]] +name = "xcb" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de" +dependencies = [ + "libc", + "log", +] + [[package]] name = "xcb" version = "0.9.0" @@ -6513,6 +6547,17 @@ dependencies = [ "xkbcommon-sys", ] +[[package]] +name = "xkbcommon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce" +dependencies = [ + "libc", + "memmap", + "xcb 0.8.2", +] + [[package]] name = "xkbcommon-sys" version = "0.7.4" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index d472f29581..c67ee72d83 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -45,6 +45,7 @@ iced = {package = "iced_native", git = "https://github.com/hecrj/iced", rev = "8 iced_winit = {git = "https://github.com/hecrj/iced", rev = "8d882d787e6b7fd7c2435f42f82933e2ed904edf"} window_clipboard = "0.2" glyph_brush = "0.7.0" +keyboard-keynames = "0.1.0" # ECS specs = {git = "https://github.com/amethyst/specs.git", rev = "5a9b71035007be0e3574f35184acac1cd4530496"} diff --git a/voxygen/src/hud/buttons.rs b/voxygen/src/hud/buttons.rs index efe821615a..cd3c0fd20f 100644 --- a/voxygen/src/hud/buttons.rs +++ b/voxygen/src/hud/buttons.rs @@ -126,6 +126,7 @@ impl<'a> Widget for Buttons<'a> { Some(inv) => inv, None => return None, }; + let key_layout = &self.global_state.window.key_layout; let localized_strings = self.localized_strings; let arrow_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8; //Animation timer @@ -184,13 +185,13 @@ impl<'a> Widget for Buttons<'a> { .controls .get_binding(GameInput::Bag) { - Text::new(bag.to_string().as_str()) + Text::new(bag.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.bag, 0.0, 0.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.bag_text_bg, ui); - Text::new(bag.to_string().as_str()) + Text::new(bag.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.bag_text_bg, 1.0, 1.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) @@ -245,13 +246,13 @@ impl<'a> Widget for Buttons<'a> { .controls .get_binding(GameInput::Settings) { - Text::new(settings.to_string().as_str()) + Text::new(settings.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.settings_button, 0.0, 0.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.settings_text_bg, ui); - Text::new(settings.to_string().as_str()) + Text::new(settings.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.settings_text_bg, 1.0, 1.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) @@ -283,13 +284,13 @@ impl<'a> Widget for Buttons<'a> { .controls .get_binding(GameInput::Social) { - Text::new(social.to_string().as_str()) + Text::new(social.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.social_button, 0.0, 0.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.social_text_bg, ui); - Text::new(social.to_string().as_str()) + Text::new(social.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.social_text_bg, 1.0, 1.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) @@ -320,13 +321,13 @@ impl<'a> Widget for Buttons<'a> { .controls .get_binding(GameInput::Map) { - Text::new(map.to_string().as_str()) + Text::new(map.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.map_button, 0.0, 0.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.map_text_bg, ui); - Text::new(map.to_string().as_str()) + Text::new(map.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.map_text_bg, 1.0, 1.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) @@ -362,13 +363,13 @@ impl<'a> Widget for Buttons<'a> { .controls .get_binding(GameInput::Spellbook) { - Text::new(spell.to_string().as_str()) + Text::new(spell.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.spellbook_button, 0.0, 0.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.spellbook_text_bg, ui); - Text::new(spell.to_string().as_str()) + Text::new(spell.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.spellbook_text_bg, 1.0, 1.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) @@ -422,13 +423,13 @@ impl<'a> Widget for Buttons<'a> { .controls .get_binding(GameInput::Crafting) { - Text::new(crafting.to_string().as_str()) + Text::new(crafting.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.crafting_button, 0.0, 0.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.crafting_text_bg, ui); - Text::new(crafting.to_string().as_str()) + Text::new(crafting.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.crafting_text_bg, 1.0, 1.0) .font_size(10) .font_id(self.fonts.cyri.conrod_id) diff --git a/voxygen/src/hud/group.rs b/voxygen/src/hud/group.rs index 35609660d2..6eedd7dc94 100644 --- a/voxygen/src/hud/group.rs +++ b/voxygen/src/hud/group.rs @@ -151,6 +151,7 @@ impl<'a> Widget for Group<'a> { let widget::UpdateArgs { state, ui, .. } = args; let mut events = Vec::new(); let localized_strings = self.localized_strings; + let key_layout = &self.global_state.window.key_layout; let buff_ani = ((self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8) + 0.5; //Animation timer let debug_on = self.global_state.settings.interface.toggle_debug; let offset = if debug_on { 270.0 } else { 0.0 }; @@ -802,7 +803,7 @@ impl<'a> Widget for Group<'a> { .settings .controls .get_binding(GameInput::AcceptGroupInvite) - .map_or_else(|| "".into(), |key| key.to_string()); + .map_or_else(|| "".into(), |key| key.display_string(key_layout)); if Button::image(self.imgs.button) .w_h(90.0, 22.0) .bottom_left_with_margins_on(state.ids.bg, 15.0, 15.0) @@ -827,7 +828,7 @@ impl<'a> Widget for Group<'a> { .settings .controls .get_binding(GameInput::DeclineGroupInvite) - .map_or_else(|| "".into(), |key| key.to_string()); + .map_or_else(|| "".into(), |key| key.display_string(key_layout)); if Button::image(self.imgs.button) .w_h(90.0, 22.0) .bottom_right_with_margins_on(state.ids.bg, 15.0, 15.0) diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index ebcd13c1e2..4c68dc1bab 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -953,6 +953,7 @@ impl Hud { let fps = global_state.clock.stats().average_tps; let version = common::util::DISPLAY_VERSION_LONG.clone(); let i18n = &*global_state.i18n.read(); + let key_layout = &global_state.window.key_layout; if self.show.ingame { let ecs = client.state().ecs(); @@ -1389,6 +1390,7 @@ impl Hud { &global_state.settings.controls, // If we're currently set to interact with the item... active, + &global_state.window.key_layout, ) .x_y(0.0, 100.0) .position_ingame(pos) @@ -1434,6 +1436,7 @@ impl Hud { &self.fonts, &global_state.settings.controls, true, + &global_state.window.key_layout, ) .x_y(0.0, 100.0) .position_ingame(over_pos) @@ -1791,21 +1794,19 @@ impl Hud { .mid_top_with_margin_on(self.ids.intro_button, -20.0 + arrow_ani as f64) .color(Some(QUALITY_LEGENDARY)) .set(self.ids.tut_arrow, ui_widgets); - Text::new( - &i18n - .get("hud.tutorial_click_here") - .replace("{key}", toggle_cursor_key.to_string().as_str()), - ) + Text::new(&i18n.get("hud.tutorial_click_here").replace( + "{key}", + toggle_cursor_key.display_string(key_layout).as_str(), + )) .mid_top_with_margin_on(self.ids.tut_arrow, -18.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(14)) .color(BLACK) .set(self.ids.tut_arrow_txt_bg, ui_widgets); - Text::new( - &i18n - .get("hud.tutorial_click_here") - .replace("{key}", toggle_cursor_key.to_string().as_str()), - ) + Text::new(&i18n.get("hud.tutorial_click_here").replace( + "{key}", + toggle_cursor_key.display_string(key_layout).as_str(), + )) .bottom_right_with_margins_on(self.ids.tut_arrow_txt_bg, 1.0, 1.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(14)) @@ -2071,7 +2072,7 @@ impl Hud { Text::new( &i18n .get("hud.press_key_to_toggle_keybindings_fmt") - .replace("{key}", help_key.to_string().as_str()), + .replace("{key}", help_key.display_string(key_layout).as_str()), ) .color(TEXT_COLOR) .down_from(self.ids.num_particles, 5.0) @@ -2085,11 +2086,10 @@ impl Hud { .controls .get_binding(GameInput::ToggleDebug) { - Text::new( - &i18n - .get("hud.press_key_to_toggle_debug_info_fmt") - .replace("{key}", toggle_debug_key.to_string().as_str()), - ) + Text::new(&i18n.get("hud.press_key_to_toggle_debug_info_fmt").replace( + "{key}", + toggle_debug_key.display_string(key_layout).as_str(), + )) .color(TEXT_COLOR) .down_from(self.ids.help_info, 5.0) .font_id(self.fonts.cyri.conrod_id) @@ -2102,7 +2102,7 @@ impl Hud { Text::new( &i18n .get("hud.press_key_to_show_keybindings_fmt") - .replace("{key}", help_key.to_string().as_str()), + .replace("{key}", help_key.display_string(key_layout).as_str()), ) .color(TEXT_COLOR) .bottom_left_with_margins_on(ui_widgets.window, 210.0, 10.0) @@ -2116,11 +2116,10 @@ impl Hud { .controls .get_binding(GameInput::ToggleDebug) { - Text::new( - &i18n - .get("hud.press_key_to_show_debug_info_fmt") - .replace("{key}", toggle_debug_key.to_string().as_str()), - ) + Text::new(&i18n.get("hud.press_key_to_show_debug_info_fmt").replace( + "{key}", + toggle_debug_key.display_string(key_layout).as_str(), + )) .color(TEXT_COLOR) .top_left_with_margins_on(ui_widgets.window, 5.0, 5.0) .font_id(self.fonts.cyri.conrod_id) @@ -2133,11 +2132,10 @@ impl Hud { .controls .get_binding(GameInput::ToggleLantern) { - Text::new( - &i18n - .get("hud.press_key_to_toggle_lantern_fmt") - .replace("{key}", toggle_lantern_key.to_string().as_str()), - ) + Text::new(&i18n.get("hud.press_key_to_toggle_lantern_fmt").replace( + "{key}", + toggle_lantern_key.display_string(key_layout).as_str(), + )) .color(TEXT_COLOR) .up_from(self.ids.help_info, 2.0) .font_id(self.fonts.cyri.conrod_id) @@ -2259,6 +2257,7 @@ impl Hud { &global_state.i18n, &global_state.settings, &prompt_dialog_settings, + &global_state.window.key_layout, ) .set(self.ids.prompt_dialog, ui_widgets) { @@ -2894,7 +2893,7 @@ impl Hud { if self.show.free_look { let msg = i18n .get("hud.free_look_indicator") - .replace("{key}", freelook_key.to_string().as_str()); + .replace("{key}", freelook_key.display_string(key_layout).as_str()); Text::new(&msg) .color(TEXT_BG) .mid_top_with_margin_on(ui_widgets.window, indicator_offset) @@ -2937,7 +2936,7 @@ impl Hud { if self.show.camera_clamp { let msg = i18n .get("hud.camera_clamp_indicator") - .replace("{key}", cameraclamp_key.to_string().as_str()); + .replace("{key}", cameraclamp_key.display_string(key_layout).as_str()); Text::new(&msg) .color(TEXT_BG) .mid_top_with_margin_on(ui_widgets.window, indicator_offset) diff --git a/voxygen/src/hud/overitem.rs b/voxygen/src/hud/overitem.rs index 86f3a13927..5d0f32249a 100644 --- a/voxygen/src/hud/overitem.rs +++ b/voxygen/src/hud/overitem.rs @@ -10,6 +10,7 @@ use conrod_core::{ use std::borrow::Cow; pub const TEXT_COLOR: Color = Color::Rgba(0.61, 0.61, 0.89, 1.0); +use keyboard_keynames::key_layout::KeyLayout; widget_ids! { struct Ids { @@ -34,6 +35,7 @@ pub struct Overitem<'a> { #[conrod(common_builder)] common: widget::CommonBuilder, active: bool, + key_layout: &'a Option, } impl<'a> Overitem<'a> { @@ -44,6 +46,7 @@ impl<'a> Overitem<'a> { fonts: &'a Fonts, controls: &'a ControlSettings, active: bool, + key_layout: &'a Option, ) -> Self { Self { name, @@ -53,6 +56,7 @@ impl<'a> Overitem<'a> { controls, common: widget::CommonBuilder::default(), active, + key_layout, } } } @@ -143,7 +147,7 @@ impl<'a> Widget for Overitem<'a> { .depth(self.distance_from_player_sqr + 1.0) .parent(id) .set(state.ids.btn_bg, ui); - Text::new(&format!("{}", key_button)) + Text::new(key_button.display_string(self.key_layout).as_str()) .font_id(self.fonts.cyri.conrod_id) .font_size(btn_font_size as u32) .color(TEXT_COLOR) diff --git a/voxygen/src/hud/prompt_dialog.rs b/voxygen/src/hud/prompt_dialog.rs index 3c358f08fd..7886f8b5eb 100644 --- a/voxygen/src/hud/prompt_dialog.rs +++ b/voxygen/src/hud/prompt_dialog.rs @@ -11,6 +11,7 @@ use conrod_core::{ widget::{self, Button, Image, Text}, widget_ids, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, }; +use keyboard_keynames::key_layout::KeyLayout; widget_ids! { struct Ids { @@ -34,6 +35,7 @@ pub struct PromptDialog<'a> { localized_strings: &'a AssetHandle, settings: &'a Settings, prompt_dialog_settings: &'a PromptDialogSettings, + key_layout: &'a Option, } impl<'a> PromptDialog<'a> { @@ -44,6 +46,7 @@ impl<'a> PromptDialog<'a> { localized_strings: &'a AssetHandle, settings: &'a Settings, prompt_dialog_settings: &'a PromptDialogSettings, + key_layout: &'a Option, ) -> Self { Self { imgs, @@ -52,6 +55,7 @@ impl<'a> PromptDialog<'a> { common: widget::CommonBuilder::default(), settings, prompt_dialog_settings, + key_layout, } } } @@ -88,12 +92,12 @@ impl<'a> Widget for PromptDialog<'a> { .settings .controls .get_binding(GameInput::AcceptGroupInvite) - .map_or_else(|| "".into(), |key| key.to_string()); + .map_or_else(|| "".into(), |key| key.display_string(self.key_layout)); let decline_key = self .settings .controls .get_binding(GameInput::DeclineGroupInvite) - .map_or_else(|| "".into(), |key| key.to_string()); + .map_or_else(|| "".into(), |key| key.display_string(self.key_layout)); // Window Image::new(self.imgs.prompt_top) diff --git a/voxygen/src/hud/settings_window/controls.rs b/voxygen/src/hud/settings_window/controls.rs index 901be934ab..86afe48337 100644 --- a/voxygen/src/hud/settings_window/controls.rs +++ b/voxygen/src/hud/settings_window/controls.rs @@ -74,6 +74,7 @@ impl<'a> Widget for Controls<'a> { let widget::UpdateArgs { state, ui, .. } = args; let mut events = Vec::new(); + let key_layout = &self.global_state.window.key_layout; Rectangle::fill_with(args.rect.dim(), color::TRANSPARENT) .xy(args.rect.xy()) @@ -125,7 +126,7 @@ impl<'a> Widget for Controls<'a> { ) } else if let Some(key) = controls.get_binding(game_input) { ( - key.to_string(), + key.display_string(key_layout), if controls.has_conflicting_bindings(key) { TEXT_BIND_CONFLICT_COLOR } else { diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index c32b4949ac..a8c6f75b87 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -245,6 +245,7 @@ impl<'a> Widget for Skillbar<'a> { let crit_hp_color: Color = Color::Rgba(0.79, 0.19, 0.17, hp_ani); let localized_strings = self.localized_strings; + let key_layout = &self.global_state.window.key_layout; let slot_offset = 3.0; @@ -265,7 +266,7 @@ impl<'a> Widget for Skillbar<'a> { Text::new( &localized_strings .get("hud.press_key_to_respawn") - .replace("{key}", key.to_string().as_str()), + .replace("{key}", key.display_string(key_layout).as_str()), ) .mid_bottom_with_margin_on(state.ids.death_message_1_bg, -120.0) .font_size(self.fonts.cyri.scale(30)) @@ -281,7 +282,7 @@ impl<'a> Widget for Skillbar<'a> { Text::new( &localized_strings .get("hud.press_key_to_respawn") - .replace("{key}", key.to_string().as_str()), + .replace("{key}", key.display_string(key_layout).as_str()), ) .bottom_left_with_margins_on(state.ids.death_message_2_bg, 2.0, 2.0) .font_size(self.fonts.cyri.scale(30)) @@ -825,13 +826,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot1) { - Text::new(slot1.to_string().as_str()) + Text::new(slot1.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot1, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot1_text_bg, ui); - Text::new(slot1.to_string().as_str()) + Text::new(slot1.display_string(key_layout).as_str()) .bottom_left_with_margins_on(state.ids.slot1_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -844,13 +845,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot2) { - Text::new(slot2.to_string().as_str()) + Text::new(slot2.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot2, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot2_text_bg, ui); - Text::new(slot2.to_string().as_str()) + Text::new(slot2.display_string(key_layout).as_str()) .bottom_left_with_margins_on(state.ids.slot2_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -863,13 +864,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot3) { - Text::new(slot3.to_string().as_str()) + Text::new(slot3.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot3, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot3_text_bg, ui); - Text::new(slot3.to_string().as_str()) + Text::new(slot3.display_string(key_layout).as_str()) .bottom_left_with_margins_on(state.ids.slot3_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -882,13 +883,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot4) { - Text::new(slot4.to_string().as_str()) + Text::new(slot4.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot4, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot4_text_bg, ui); - Text::new(slot4.to_string().as_str()) + Text::new(slot4.display_string(key_layout).as_str()) .bottom_left_with_margins_on(state.ids.slot4_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -901,13 +902,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot5) { - Text::new(slot5.to_string().as_str()) + Text::new(slot5.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot5, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot5_text_bg, ui); - Text::new(slot5.to_string().as_str()) + Text::new(slot5.display_string(key_layout).as_str()) .bottom_left_with_margins_on(state.ids.slot5_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -920,13 +921,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot6) { - Text::new(slot6.to_string().as_str()) + Text::new(slot6.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot6, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot6_text_bg, ui); - Text::new(slot6.to_string().as_str()) + Text::new(slot6.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.slot6_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -939,13 +940,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot7) { - Text::new(slot7.to_string().as_str()) + Text::new(slot7.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot7, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot7_text_bg, ui); - Text::new(slot7.to_string().as_str()) + Text::new(slot7.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.slot7_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -958,13 +959,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot8) { - Text::new(slot8.to_string().as_str()) + Text::new(slot8.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot8, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot8_text_bg, ui); - Text::new(slot8.to_string().as_str()) + Text::new(slot8.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.slot8_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -977,13 +978,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot9) { - Text::new(slot9.to_string().as_str()) + Text::new(slot9.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot9, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot9_text_bg, ui); - Text::new(slot9.to_string().as_str()) + Text::new(slot9.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.slot9_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) @@ -996,13 +997,13 @@ impl<'a> Widget for Skillbar<'a> { .controls .get_binding(GameInput::Slot10) { - Text::new(slot10.to_string().as_str()) + Text::new(slot10.display_string(key_layout).as_str()) .top_right_with_margins_on(state.ids.slot10, 3.0, 5.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) .color(BLACK) .set(state.ids.slot10_text_bg, ui); - Text::new(slot10.to_string().as_str()) + Text::new(slot10.display_string(key_layout).as_str()) .bottom_right_with_margins_on(state.ids.slot10_text_bg, 1.0, 1.0) .font_size(self.fonts.cyri.scale(8)) .font_id(self.fonts.cyri.conrod_id) diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index b8afc8b27b..2bacb2758f 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -9,9 +9,9 @@ use crossbeam::channel; use gilrs::{EventType, Gilrs}; use hashbrown::HashMap; use itertools::Itertools; +use keyboard_keynames::key_layout::KeyLayout; use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt}; use serde::{Deserialize, Serialize}; -use std::fmt; use tracing::{error, info, warn}; use vek::*; use winit::monitor::VideoMode; @@ -320,11 +320,11 @@ pub enum KeyMouse { ScanKey(winit::event::ScanCode), } -impl fmt::Display for KeyMouse { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl KeyMouse { + pub fn display_string(&self, key_layout: &Option) -> String { use self::KeyMouse::*; use winit::event::{MouseButton, VirtualKeyCode::*}; - write!(f, "{}", match self { + let key_string = match self { Key(Key1) => "1", Key(Key2) => "2", Key(Key3) => "3", @@ -491,11 +491,20 @@ impl fmt::Display for KeyMouse { Mouse(MouseButton::Left) => "M1", Mouse(MouseButton::Right) => "M2", Mouse(MouseButton::Middle) => "M3", - Mouse(MouseButton::Other(button)) => - // Additional mouse buttons after middle click start at 1 - return write!(f, "M{}", button + 3), - ScanKey(_) => "Unknown", - }) + Mouse(MouseButton::Other(button)) => { + // Additional mouse buttons after middle click start at 1 + return format!("M{}", button + 3); + }, + ScanKey(scancode) => { + if let Some(layout) = key_layout { + return layout.get_key_as_string(*scancode); + } else { + return format!("Unknown({})", scancode); + } + }, + }; + + String::from(key_string) } } @@ -525,6 +534,7 @@ pub struct Window { // Used for screenshots & fullscreen toggle to deduplicate/postpone to after event handler take_screenshot: bool, toggle_fullscreen: bool, + pub key_layout: Option, } impl Window { @@ -600,6 +610,18 @@ impl Window { let scale_factor = window.window().scale_factor(); + let key_layout = match KeyLayout::new_from_window(window.window()) { + Ok(kl) => Some(kl), + Err(err) => { + warn!( + ?err, + "Failed to construct the scancode to keyname mapper, falling back to \ + displaying Unknown()." + ); + None + }, + }; + let mut this = Self { renderer: Renderer::new( device, @@ -631,6 +653,7 @@ impl Window { message_receiver, take_screenshot: false, toggle_fullscreen: false, + key_layout, }; this.set_fullscreen_mode(settings.graphics.fullscreen);