Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions docs/keyboard-letter-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Layout-aware shortcuts (Windows x64)

The default `[control].keyboard_layout_mode = "physical"` preserves existing behavior.
Set it to `"layout"` and restart to interpret printable shortcut characters using
Windows' active keyboard layout. Subsequent layout changes apply live through
Unity device notifications. Release held keys before using the new layout.

For a German layout:

| Configured chord | Keys on a German keyboard |
| --- | --- |
| `/` | Shift+7 |
| `CTRL-'` | Ctrl+Shift+# |
| `ALT-^` | Alt+^ |
| `SHIFT-^` | Shift+^ |
| `Z` | Z (US physical Y position) |

Remove old Y/Z workarounds when opting in. Uppercase letter tokens name keys;
they do not request Shift. Shift needed to produce punctuation is added to the
explicit configured modifiers. Side-specific modifiers retain their requirements.
Existing explicitly modified bindings accept extra modifiers; avoid overlapping
chords, since action dispatch order determines which matching action wins.

**German users enabling experimental shortcuts:** the upstream defaults
`show_alliance_help = "SHIFT-'"` and `show_alliance_armada = "CTRL-'"` overlap
because German apostrophe already requires Shift. Help is checked first and
captures the Armada chord. Use the tested remap below in the existing sections:

```toml
[control]
keyboard_layout_mode = "layout"
enable_experimental = true

[shortcuts]
show_alliance = "ALT-^"
show_alliance_help = "SHIFT-^"
show_alliance_armada = "CTRL-'"
```

This keeps upstream modifier matching and shortcut defaults unchanged.

Hints and runtime shortcut values retain configured TOML text. The internal
physical mapping is not a replacement hint. Named controls (function keys, arrows,
Space, mouse and numpad keys), hardcoded controls and Scopely shortcuts are unchanged.
Alliance Help and Armada retain the upstream `enable_experimental = true` requirement.

The resolver uses Windows character-to-key translation and supported scan-code
positions. Unshifted dead keys use a non-composing fallback: no following Space
is needed for a shortcut, and lookup does not consume pending text accents.
Characters requiring inferred Ctrl/Alt/AltGr, unsupported positions and missing
characters are disabled individually. Explicit configured Ctrl/Alt still work.

Mapping is cached per requested character and refreshed only at initialization or
a device notification. Held keys are suppressed through a layout transition until
released. Notification failure disables layout bindings until restart; there is no
polling or silent physical fallback. The runtime `[keyboard_mapping]` section gives
layout, generation and status; logs identify unresolved characters.

Layout mode is currently supported on Windows x64. Other platforms retain default
physical behavior; explicitly requesting layout mode disables printable bindings
and reports `platform_unsupported`. The experimental macOS adapter and prototype
preview/diagnostic settings are not part of this implementation.
5 changes: 5 additions & 0 deletions example_community_patch_settings_da.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# Sæt denne til sand, hvis du foretrækker at bruge Scopelys genvejstaster
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# Auf true setzen, um die Hotkeys von Scopely zu verwenden
use_scopely_hotkeys = false

# Windows x64: "physical" behält Tastenpositionen bei; "layout" folgt dem aktiven Layout.
# Erforderliches Shift wird ergänzt; Ctrl/AltGr-Zeichen bleiben nicht unterstützt.
# Layoutwechsel gelten live; gehaltene Tasten vorher loslassen. Siehe docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Optionen
# ------------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_en-GB-x-cockney.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# If you prefer to use Scopely's hotkeys set this to true
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_en-x-minionese.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# If you prefer to use Scopely's hotkeys set this to true
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# If you prefer to use Scopely's hotkeys set this to true
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# Si prefieres usar los atajos de Scopely, establece este valor en verdadero
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# Si vous préférez utiliser les raccourcis de Scopely mettez ça sur activer
use_scopely_hotkeys = false

# Windows x64 : "physical" conserve les positions ; "layout" suit la disposition active.
# Maj nécessaire est ajouté ; les caractères nécessitant Ctrl/AltGr ne sont pas pris en charge.
# Les changements sont appliqués en direct ; relâchez les touches. Voir docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_nl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# Als je de Scopely sneltoetsen prefereerd over die van de mod, schakel dit dan aan
use_scopely_hotkeys = false

# Windows x64: "physical" behoudt toetsposities; "layout" volgt de actieve indeling.
# Vereiste Shift wordt toegevoegd; tekens met Ctrl/AltGr worden niet ondersteund.
# Wisselen werkt direct; laat ingedrukte toetsen los. Zie docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_ru.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# Включите этот параметр, если предпочитаете горячие клавиши Scopely
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
5 changes: 5 additions & 0 deletions example_community_patch_settings_tlh.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ queue_enabled = true
# If you prefer Daq lo' Scopely's hotkeys cher this Daq teH
use_scopely_hotkeys = false

# Windows x64: "physical" preserves positions; "layout" follows the active layout.
# Required Shift is inferred; characters requiring Ctrl/AltGr are unsupported.
# Layout changes apply live; release held keys. See docs/keyboard-letter-layout.md.
keyboard_layout_mode = "physical"

# Subgroup: Options
# -----------------

Expand Down
11 changes: 11 additions & 0 deletions mods/src/config.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "config.h"
#include "file.h"
#include "patches/mapkey.h"
#include "patches/keyboard_layout.h"
#include "prime/KeyCode.h"
#include "ship_name_match.h"
#include "str_utils.h"
Expand Down Expand Up @@ -709,6 +710,7 @@ void parse_config_shortcut_value(toml::table& new_config, std::string_view item,

if (mapKey.Key != KeyCode::None) {
keyAdded = true;
keyboard_layout::RegisterShortcut(mapKey.Key);
MapKey::AddMappedKey(gameFunction, std::move(mapKey));
} else if (!wantedKey.empty()) {
spdlog::warn("Invalid shortcut token [shortcuts].{} token='{}' value='{}'; ignoring token.",
Expand Down Expand Up @@ -939,6 +941,14 @@ void Config::Load()
get_config_or_default(config, parsed, "control", "hotkeys_extended", DCC::hotkeys_extended, write_config);
this->use_scopely_hotkeys =
get_config_or_default(config, parsed, "control", "use_scopely_hotkeys", DCC::use_scopely_hotkeys, write_config);
this->keyboard_layout_mode = get_config_or_default(
config, parsed, "control", "keyboard_layout_mode", std::string(DCC::keyboard_layout_mode), write_config);
if (this->keyboard_layout_mode != "physical" && this->keyboard_layout_mode != "layout") {
spdlog::warn("Invalid keyboard_layout_mode '{}'; using physical", this->keyboard_layout_mode);
this->keyboard_layout_mode = "physical";
parsed["control"].as_table()->insert_or_assign("keyboard_layout_mode", this->keyboard_layout_mode);
}
keyboard_layout::Configure(this->keyboard_layout_mode);
this->select_timer =
get_config_or_default(config, parsed, "control", "select_timer", DCC::select_timer, write_config);
this->enable_experimental =
Expand Down Expand Up @@ -1410,6 +1420,7 @@ void Config::Load()
std::filesystem::remove(FILE_DEF_PARSED);
}

keyboard_layout::InitializeDiagnostics(parsed);
Config::Save(parsed, File::Vars());

std::cout << "\n\n-----------------------------\n\n"
Expand Down
1 change: 1 addition & 0 deletions mods/src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class Config final
bool hotkeys_enabled;
bool hotkeys_extended;
bool use_scopely_hotkeys;
std::string keyboard_layout_mode;
bool use_presets_as_default;
bool enable_experimental;
float default_system_zoom;
Expand Down
1 change: 1 addition & 0 deletions mods/src/defaultconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace Control
constexpr bool hotkeys_enabled = true;
constexpr bool hotkeys_extended = true;
constexpr bool use_scopely_hotkeys = false;
constexpr const char* keyboard_layout_mode = "physical";
constexpr bool queue_enabled = true;
constexpr auto select_timer = 500;
} // namespace Control
Expand Down
3 changes: 3 additions & 0 deletions mods/src/patches/key.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ const std::unordered_map<std::string, KeyCode> Key::mappedKeys = {
{"MOUSE6", KeyCode::Mouse6},
{"SPACE", KeyCode::Space},
{"MINUS", KeyCode::Minus},
{"EQUAL", KeyCode::Equals},
// '-' separates modifiers and '|' separates alternative bindings in config.
{"PIPE", KeyCode::Pipe},
{"_", KeyCode::Underscore},
{",", KeyCode::Comma},
{";", KeyCode::Semicolon},
Expand Down
Loading
Loading