Customize hotkey categories & ordering, prepare for translation.

- adds JSON files to specify the human-readable categorization, name and
description of hotkeys.
- clean up code

Translation support via messages.json not yet added - the strings need
another pass and that avoids translators doing redundant work. See D3641

Refs #5867, Refs #5996

Differential Revision: https://code.wildfiregames.com/D3596
This was SVN commit r25023.
This commit is contained in:
wraitii
2021-03-06 18:11:41 +00:00
parent 3b3a297cca
commit 09ad8bfbe5
10 changed files with 884 additions and 70 deletions
@@ -0,0 +1,67 @@
/**
*
*/
class HotkeyMetadata
{
constructor()
{
this.DEFAULT_CATEGORY = "other";
this.categories = {};
this.hotkeys = {};
this.parseSpec();
}
parseSpec()
{
let files = this.getFiles();
let hotkey_i = 0;
let categories = {
[this.DEFAULT_CATEGORY]: {
"name": markForTranslation("Other Hotkeys"),
"desc": markForTranslation("Other Hotkeys"),
}
};
for (let file of files)
{
let data = Engine.ReadJSONFile(file);
if (data.categories)
for (let cat in data.categories)
categories[cat] = data.categories[cat];
if (data.hotkeys)
for (let hotkey in data.hotkeys)
{
this.hotkeys[hotkey] = data.hotkeys[hotkey];
this.hotkeys[hotkey].order = hotkey_i++;
this.hotkeys[hotkey].categories = data.hotkeys[hotkey].categories || [this.DEFAULT_CATEGORY];
}
if (data.mapped_hotkeys)
for (let cat in data.mapped_hotkeys)
for (let hotkey in data.mapped_hotkeys[cat])
{
if (data.mapped_hotkeys[cat][hotkey].categories)
warn("Categories will be overwritten for mapped hotkey " + hotkey);
this.hotkeys[hotkey] = data.mapped_hotkeys[cat][hotkey];
this.hotkeys[hotkey].order = hotkey_i++;
this.hotkeys[hotkey].categories = [cat];
}
}
// Sort categories (JS objects are (in this case) sorted by insertion order).
this.categories = {};
let keys = Object.keys(categories).sort((a, b) => {
if (a === this.DEFAULT_CATEGORY || b === this.DEFAULT_CATEGORY)
return a === this.DEFAULT_CATEGORY ? 1 : -1;
if (categories[a].order === undefined || categories[b].order === undefined)
return categories[a].order === undefined ? -1 : 1; // Likely to keep alphabetical order.
return categories[a].order - categories[b].order;
});
for (let key of keys)
this.categories[key] = categories[key];
// TODO: validate that categories exist.
}
getFiles()
{
return Engine.ListDirectoryFiles("gui/hotkeys/spec/", "*.json");
}
}
@@ -4,8 +4,9 @@
*/
class HotkeyPicker
{
constructor(onClose, name, combinations)
constructor(metadata, onClose, name, combinations)
{
this.metadata = metadata;
this.name = name;
this.combinations = combinations;
this.window = Engine.GetGUIObjectByName("hotkeyPicker");
@@ -13,7 +14,16 @@ class HotkeyPicker
this.enteringInput = -1;
Engine.GetGUIObjectByName("hotkeyPickerTitle").caption = translate(this.name);
if (this.metadata.hotkeys[name])
{
Engine.GetGUIObjectByName("hotkeyPickerTitle").caption = translate(this.metadata.hotkeys[name].name);
Engine.GetGUIObjectByName("hotkeyPickerDescHotkey").caption = translate(this.metadata.hotkeys[name].desc);
}
else
{
Engine.GetGUIObjectByName("hotkeyPickerTitle").caption = this.name;
Engine.GetGUIObjectByName("hotkeyPickerDescHotkey").hidden = true;
}
this.setupCombinations();
this.render();
@@ -41,8 +51,8 @@ class HotkeyPicker
for (let i = 0; i < 4; ++i)
{
let s = Engine.GetGUIObjectByName("combination[" + i + "]").size;
s.top = +i * 60 + 90;
s.bottom = +i * 60 + 120;
s.top = +i * 60 + 120;
s.bottom = +i * 60 + 150;
Engine.GetGUIObjectByName("combination[" + i + "]").size = s;
Engine.GetGUIObjectByName("combNb[" + i + "]").caption = sprintf(translate("#%i"), i);
@@ -1,16 +1,33 @@
class HotkeysPage
{
constructor()
constructor(metadata)
{
this.metadata = metadata;
Engine.GetGUIObjectByName("hotkeyList").onMouseLeftDoubleClickItem = () => {
let idx = Engine.GetGUIObjectByName("hotkeyList").selected;
let picker = new HotkeyPicker(
this.metadata,
this.onHotkeyPicked.bind(this),
Engine.GetGUIObjectByName("hotkeyList").list_data[idx],
clone(this.hotkeys[Engine.GetGUIObjectByName("hotkeyList").list_data[idx]])
);
};
Engine.GetGUIObjectByName("hotkeyList").onHoverChange = () => this.onHoverChange();
Engine.GetGUIObjectByName("hotkeyFilter").onSelectionChange = () => this.setupHotkeyList();
Engine.GetGUIObjectByName("hotkeyFilter").onHoverChange = () => {
let dropdown = Engine.GetGUIObjectByName("hotkeyFilter");
if (dropdown.hovered === -1)
dropdown.tooltip = "";
else
{
if (dropdown.list_data[dropdown.hovered] == -1)
dropdown.tooltip = "";
else
dropdown.tooltip = translate(this.categories[dropdown.list_data[dropdown.hovered]].desc);
}
};
Engine.GetGUIObjectByName("hotkeyTextFilter").onTextEdit = () => this.setupHotkeyList();
@@ -29,12 +46,39 @@ class HotkeysPage
this.setupHotkeyList();
}
setupHotkeyData()
{
let hotkeydata = Engine.GetHotkeyMap();
this.hotkeys = hotkeydata;
let categories = clone(this.metadata.categories);
for (let name in categories)
categories[name].hotkeys = [];
for (let hotkeyName in this.hotkeys)
{
if (this.metadata.hotkeys[hotkeyName])
for (let cat of this.metadata.hotkeys[hotkeyName].categories)
categories[cat].hotkeys.push(hotkeyName);
else
categories[this.metadata.DEFAULT_CATEGORY].hotkeys.push(hotkeyName);
}
for (let cat in categories)
categories[cat].hotkeys.sort((a, b) => {
if (!this.metadata.hotkeys[a] || !this.metadata.hotkeys[b])
return !this.metadata.hotkeys[a] ? 1 : -1;
return this.metadata.hotkeys[a].order - this.metadata.hotkeys[b].order;
});
for (let cat in categories)
if (categories[cat].hotkeys.length === 0)
delete categories[cat];
this.categories = categories;
}
setupFilters()
{
let dropdown = Engine.GetGUIObjectByName("hotkeyFilter");
let names = [];
for (let cat in this.categories)
names.push(this.categories[cat].label);
names.push(translate(this.categories[cat].name));
dropdown.list = [translate("All Hotkeys")].concat(names);
dropdown.list_data = [-1].concat(Object.keys(this.categories));
dropdown.selected = 0;
@@ -45,28 +89,34 @@ class HotkeysPage
let hotkeyList = Engine.GetGUIObjectByName("hotkeyList");
hotkeyList.selected = -1;
let textFilter = Engine.GetGUIObjectByName("hotkeyTextFilter").caption;
let hotkeys;
let dropdown = Engine.GetGUIObjectByName("hotkeyFilter");
if (dropdown.selected && dropdown.selected !== 0)
{
let category = this.categories[dropdown.list_data[dropdown.selected]];
// This is inefficient but it seems fast enough.
let hotkeys = category.hotkeys.filter(x => translate(x[0]).indexOf(textFilter) !== -1);
hotkeyList.list_name = hotkeys.map(x => translate(x[0]));
hotkeyList.list_mapping = hotkeys.map(x => formatHotkeyCombinations(x[1]));
hotkeyList.list = hotkeys.map(() => 0);
hotkeyList.list_data = hotkeys.map(x => x[0]);
}
hotkeys = this.categories[dropdown.list_data[dropdown.selected]].hotkeys;
else
hotkeys = Object.values(this.categories).map(x => x.hotkeys).flat();
hotkeys = hotkeys.filter(x => {
return x.indexOf(textFilter) !== -1 ||
translate(this.metadata.hotkeys[x]?.name || x).indexOf(textFilter) !== -1;
});
hotkeyList.list_name = hotkeys.map(x => translate(this.metadata.hotkeys[x]?.name || x));
hotkeyList.list_mapping = hotkeys.map(x => formatHotkeyCombinations(this.hotkeys[x]));
hotkeyList.list = hotkeys.map(() => 0);
hotkeyList.list_data = hotkeys.map(x => x);
}
onHoverChange()
{
let hotkeyList = Engine.GetGUIObjectByName("hotkeyList");
if (hotkeyList.hovered === -1)
hotkeyList.tooltip = "";
else
{
// TODO SM62+ : refactor using flat()
let flattened = [];
for (let cat in this.categories)
flattened = flattened.concat(this.categories[cat].hotkeys);
flattened = flattened.filter(x => translate(x[0]).indexOf(textFilter) !== -1);
hotkeyList.list_name = flattened.map(x => translate(x[0]));
hotkeyList.list_mapping = flattened.map(x => formatHotkeyCombinations(x[1]));
hotkeyList.list = flattened.map(() => 0);
hotkeyList.list_data = flattened.map(x => x[0]);
let hotkey = hotkeyList.list_data[hotkeyList.hovered];
let tooltip = this.metadata.hotkeys[hotkey]?.desc || markForTranslation("No tooltip available");
hotkeyList.tooltip = translate(tooltip);
}
}
@@ -94,48 +144,6 @@ class HotkeysPage
this.setupHotkeyList();
}
setupHotkeyData()
{
let hotkeydata = Engine.GetHotkeyMap();
this.hotkeys = hotkeydata;
let categories = {
"other": {
"label": translate("Other hotkeys"),
"hotkeys": []
}
};
let n_categories = 1;
for (let hotkeyName in this.hotkeys)
{
let category = "other";
let firstdot = hotkeyName.indexOf('.');
if (firstdot !== -1)
category = hotkeyName.substr(0, firstdot);
if (!(category in categories))
{
if (n_categories > 18)
category = "other";
categories[category] = {
"label": category,
"hotkeys": []
};
}
categories[category].hotkeys.push([hotkeyName, this.hotkeys[hotkeyName]]);
}
// Remove categories that are too small to deserve a tab.
for (let cat of Object.keys(categories))
if (categories[cat].hotkeys.length < 3)
{
categories.other.hotkeys = categories.other.hotkeys.concat(categories[cat].hotkeys);
delete categories[cat];
}
for (let cat in categories)
categories[cat].hotkeys = categories[cat].hotkeys.sort();
this.categories = categories;
}
resetUserHotkeys()
{
messageBox(
@@ -177,7 +185,7 @@ class HotkeysPage
}
function init(data)
function init()
{
let hotkeyPage = new HotkeysPage(data);
let hotkeyPage = new HotkeysPage(new HotkeyMetadata());
}
@@ -66,13 +66,17 @@
<object name="hotkeyPicker" type="image" sprite="BackgroundTranslucent" hidden="true" z="100">
<object type="image"
style="ModernDialog"
size="50%-300 50%-190 50%+300 50%+190"
size="50%-300 50%-205 50%+300 50%+205"
>
<object name="hotkeyPickerTitle" style="ModernLabelText" type="text" size="50%-128 -16 50%+128 16">
<translatableAttribute id="caption">Hotkey</translatableAttribute>
</object>
<object name="hotkeyPickerDesc" style="ModernLabelText" type="text" size="8 20 100%-8 66">
<object name="hotkeyPickerDescHotkey" style="ModernLabelText" type="text" size="8 30 100%-8 60">
<translatableAttribute id="caption">Hotkey Description</translatableAttribute>
</object>
<object name="hotkeyPickerDesc" style="ModernLabelText" type="text" size="8 60 100%-8 120">
<translatableAttribute id="caption">Click on any mapping to modify it.\n You may have up to 4 different hotkeys.</translatableAttribute>
</object>
@@ -0,0 +1,140 @@
{
"categories": {
"camera": {
"name": "Camera",
"desc": "Camera-related hotkeys"
}
},
"mapped_hotkeys": {
"camera": {
"camera.reset": {
"name": "Reset Camera",
"desc": "Reset camera rotation to default."
},
"camera.follow": {
"name": "Follow Unit",
"desc": "Follow the first unit in the selection"
},
"camera.rallypointfocus": {
"name": "Focus on rallypoint",
"desc": "Focus the camera on the rally point of the selected building"
},
"camera.zoom.in": {
"name": "Zoom in",
"desc": "Zoom camera in (continuous control)"
},
"camera.zoom.out": {
"name": "Zoom out",
"desc": "Zoom camera out (continuous control)"
},
"camera.zoom.wheel.in": {
"name": "Zoom in (step-by-step)",
"desc": "Zoom camera in (stepped control)"
},
"camera.zoom.wheel.out": {
"name": "Zoom out (step-by-step)",
"desc": "Zoom camera out (stepped control)"
},
"camera.rotate.up": {
"name": "Rotate up",
"desc": "Rotate camera to look upwards"
},
"camera.rotate.down": {
"name": "Rotate Down",
"desc": "Rotate camera to look downwards"
},
"camera.rotate.cw": {
"name": "Rotate clock-wise",
"desc": "Rotate camera clockwise around terrain"
},
"camera.rotate.ccw": {
"name": "Rotate counter-clockwise",
"desc": "Rotate camera anticlockwise around terrain"
},
"camera.rotate.wheel.cw": {
"name": "Rotate clock-wise",
"desc": "Rotate camera clockwise around terrain (stepped control)"
},
"camera.rotate.wheel.ccw": {
"name": "Rotate counter-clockwise",
"desc": "Rotate camera anticlockwise around terrain (stepped control)"
},
"camera.pan": {
"name": "Pan camera",
"desc": "Enable scrolling by moving mouse"
},
"camera.left": {
"name": "Scroll/Rotate left",
"desc": "Scroll or rotate left"
},
"camera.right": {
"name": "Scroll/Rotate right",
"desc": "Scroll or rotate right"
},
"camera.up": {
"name": "Scroll/Rotate up",
"desc": "Scroll or rotate up/forwards"
},
"camera.down": {
"name": "Scroll/Rotate down",
"desc": "Scroll or rotate down/backwards"
},
"camera.scroll.speed.increase": {
"name": "Increase scroll speed",
"desc": "Increase scroll speed"
},
"camera.scroll.speed.decrease": {
"name": "Decrease scroll speed",
"desc": "Decrease scroll speed"
},
"camera.rotate.speed.increase": {
"name": "Increase rotation speed",
"desc": "Increase rotation speed"
},
"camera.rotate.speed.decrease": {
"name": "Decrease rotation speed",
"desc": "Decrease rotation speed"
},
"camera.zoom.speed.increase": {
"name": "Increase zoom speed",
"desc": "Increase zoom speed"
},
"camera.zoom.speed.decrease": {
"name": "Decrease zoom speed",
"desc": "Decrease zoom speed"
},
"camera.jump.1": {
"name": "Jump to camera 1",
"desc": "Jump to camera position 1 (see Set Jump #1)"
},
"camera.jump.2": {
"name": "Jump to camera 2",
"desc": "Jump to camera position 2 (see Set Jump #2)"
},
"camera.jump.3": {
"name": "Jump to camera 3",
"desc": "Jump to camera position 3 (see Set Jump #3)"
},
"camera.jump.4": {
"name": "Jump to camera 4",
"desc": "Jump to camera position 4 (see Set Jump #4)"
},
"camera.jump.set.1": {
"name": "Set camera jump 1",
"desc": "Set camera jump position 1"
},
"camera.jump.set.2": {
"name": "Set camera jump 2",
"desc": "Set camera jump position 2"
},
"camera.jump.set.3": {
"name": "Set camera jump 3",
"desc": "Set camera jump position 3"
},
"camera.jump.set.4": {
"name": "Set camera jump 4",
"desc": "Set camera jump position 4"
}
}
}
}
@@ -0,0 +1,100 @@
{
"categories": {
"general": {
"name": "General",
"desc": "General hotkeys"
}
},
"mapped_hotkeys": {
"general": {
"exit": {
"name": "Exit to desktop",
"desc": "Exit to desktop"
},
"cancel": {
"name": "Close/Cancel",
"desc": "Close or cancel the current dialog box/popup"
},
"confirm": {
"name": "Confirm",
"desc": "Confirm the current command"
},
"pause": {
"name": "Pause/Unpause",
"desc": "Pause/unpause game"
},
"screenshot": {
"name": "Screenshot",
"desc": "Take PNG screenshot"
},
"bigscreenshot": {
"name": "Big screenshot",
"desc": "Take large BMP screenshot"
},
"togglefullscreen": {
"name": "Toggle Fullscreen",
"desc": "Toggle fullscreen/windowed mode"
},
"screenshot.watermark": {
"name": "Toggle watermark",
"desc": "Toggle product/company watermark for official screenshots"
},
"wireframe": {
"name": "Toggle wireframe mode",
"desc": "Toggle wireframe mode"
},
"copy": {
"name": "Copy to clipboard",
"desc": "Copy to clipboard"
},
"paste": {
"name": "Paste from clipboard",
"desc": "Paste from clipboard"
},
"cut": {
"name": "Cut to clipboard",
"desc": "Cut selected text and copy to the clipboard"
},
"console.toggle": {
"name": "Toggle Console",
"desc": "Open/close console"
},
"profile.toggle": {
"name": "Toggle profiler",
"desc": "Enable/disable real-time profiler"
},
"profile.save": {
"name": "Save profile",
"desc": "Save current profiler data to logs/profile.txt"
},
"profile2.toggle": {
"name": "Toggle profiler2",
"desc": "Enable/disable HTTP/GPU modes for new profiler"
},
"tab.next": {
"name": "Next tab",
"desc": "Show the next tab"
},
"tab.prev": {
"name": "Previous tab",
"desc": "Show the previous tab"
},
"text.delete.left": {
"name": "Delete before cursor",
"desc": "Delete word to the left of cursor"
},
"text.delete.right": {
"name": "Delete after cursor",
"desc": "Delete word to the right of cursor"
},
"text.move.left": {
"name": "Move cursor to left word",
"desc": "Move cursor to start of word to the left of cursor"
},
"text.move.right": {
"name": "Move cursor to right word",
"desc": "Move cursor to start of word to the right of cursor"
}
}
}
}
@@ -0,0 +1,16 @@
{
"categories": {
"gamesetup": {
"name": "Game Setup",
"desc": "Hotkeys active in the game setup screen."
}
},
"mapped_hotkeys": {
"gamesetup": {
"gamesetup.mapbrowser.open": {
"name": "Open map browser",
"desc": "Open the map browser."
}
}
}
}
@@ -0,0 +1,152 @@
{
"categories": {
"ingame": {
"name": "In-game",
"desc": "In-game hotkeys."
}
},
"mapped_hotkeys": {
"ingame": {
"session.kill": {
"name": "Destroy selected units",
"desc": "Destroy selected units"
},
"session.noconfirmation": {
"name": "Destroy without confirmation",
"desc": "Do not ask confirmation when deleting a building/unit"
},
"session.stop": {
"name": "Stop units",
"desc": "Stop the current action"
},
"session.backtowork": {
"name": "Back to Work",
"desc": "The unit will go back to work"
},
"session.unload": {
"name": "Unload",
"desc": "Unload garrisoned units when a building/mechanical unit is selected"
},
"session.unloadtype": {
"name": "Unload unit type",
"desc": "Modifier to unload all units of type"
},
"session.move": {
"name": "Force move",
"desc": "Modifier to move to a point instead of another action (e.g. gather)"
},
"session.attack": {
"name": "Force attack",
"desc": "Modifier to attack instead of another action (e.g. capture)"
},
"session.attackmove": {
"name": "Attack Move",
"desc": "Modifier to attackmove when clicking on a point"
},
"session.attackmoveUnit": {
"name": "Attack Move (unit only)",
"desc": "Modifier to attackmove targeting only units when clicking on a point"
},
"session.garrison": {
"name": "Garrison",
"desc": "Modifier to garrison when clicking on building"
},
"session.autorallypoint": {
"name": "Auto-rally point",
"desc": "Modifier to set the rally point on the building itself"
},
"session.guard": {
"name": "Guard",
"desc": "Modifier to escort/guard when clicking on unit/building"
},
"session.patrol": {
"name": "Patrol",
"desc": "Modifier to patrol a unit"
},
"session.repair": {
"name": "Repair",
"desc": "Modifier to repair when clicking on building/mechanical unit"
},
"session.queue": {
"name": "Queue order",
"desc": "Modifier to queue unit orders instead of replacing"
},
"session.pushorderfront": {
"name": "Push order in front",
"desc": "Modifier to execute this order, then go back to the current order."
},
"session.orderone": {
"name": "Order one unit",
"desc": "Modifier to order only one entity in selection."
},
"session.batchtrain": {
"name": "Batch production",
"desc": "Modifier to train units in batches"
},
"session.massbarter": {
"name": "Mass barter",
"desc": "Modifier to barter bunch of resources"
},
"session.masstribute": {
"name": "Mass tribute",
"desc": "Modifier to tribute bunch of resources"
},
"session.fulltradeswap": {
"name": "Set trade to 100%",
"desc": "Modifier to put the desired trade resource to 100%"
},
"session.deselectgroup": {
"name": "Deselect unit type",
"desc": "Modifier to deselect units when clicking group icon, instead of selecting"
},
"session.rotate.cw": {
"name": "Rotate building clockwise",
"desc": "Rotate building placement preview clockwise"
},
"session.rotate.ccw": {
"name": "Rotate building counterclockwise",
"desc": "Rotate building placement preview anticlockwise"
},
"session.snaptoedges": {
"name": "Toggle snap-to-edge",
"desc": "Modifier to align new structures with nearby existing structure"
},
"session.toggledefaultformation": {
"name": "Toggle default formation",
"desc": "Switch between null default formation and the last default formation used (defaults to 'box')"
},
"session.queueunit.1": {
"name": "Queue 1st unit",
"desc": "add first unit type to queue"
},
"session.queueunit.2": {
"name": "Queue 2nd unit",
"desc": "add second unit type to queue"
},
"session.queueunit.3": {
"name": "Queue 3rd unit",
"desc": "add third unit type to queue"
},
"session.queueunit.4": {
"name": "Queue 4th unit",
"desc": "add fourth unit type to queue"
},
"session.queueunit.5": {
"name": "Queue 5th unit",
"desc": "add fivth unit type to queue"
},
"session.queueunit.6": {
"name": "Queue 6th unit",
"desc": "add sixth unit type to queue"
},
"session.queueunit.7": {
"name": "Queue 7th unit",
"desc": "add seventh unit type to queue"
},
"session.queueunit.8": {
"name": "Queue 8th unit",
"desc": "add eighth unit type to queue"
}
}
}
}
@@ -0,0 +1,141 @@
{
"categories": {
"ingamegui": {
"name": "In-game GUI",
"desc": "In-game GUI hotkeys."
}
},
"mapped_hotkeys": {
"ingamegui": {
"quicksave": {
"name": "Quicksave",
"desc": "quicksave"
},
"quickload": {
"name": "Quickload",
"desc": "quickload"
},
"session.gui.toggle": {
"name": "Toggle GUI visibility",
"desc": "Toggle visibility of session GUI"
},
"chat": {
"name": "Toggle chat",
"desc": "Toggle chat window"
},
"teamchat": {
"name": "Toggle team chat",
"desc": "Toggle chat window in team chat mode"
},
"privatechat": {
"name": "Toggle private chat",
"desc": "Toggle chat window and select the previous private chat partner"
},
"summary": {
"name": "Toggle summary",
"desc": "Toggle in-game summary"
},
"lobby": {
"name": "Toggle MP lobby",
"desc": "Show the multiplayer lobby in a dialog window."
},
"structree": {
"name": "Toggle structure tree",
"desc": "Show structure tree"
},
"civinfo": {
"name": "Toggle civ info",
"desc": "Show civilization info"
},
"session.gui.menu.toggle": {
"name": "Toggle in-game menu",
"desc": "Toggle in-game menu"
},
"session.gui.diplomacy.toggle": {
"name": "Toggle diplomacy",
"desc": "Toggle in-game diplomacy page"
},
"session.gui.barter.toggle": {
"name": "Toggle barter",
"desc": "Toggle in-game barter/trade page"
},
"session.gui.objectives.toggle": {
"name": "Toggle objectives",
"desc": "Toggle in-game objectives page"
},
"session.gui.tutorial.toggle": {
"name": "Toggle tutorial",
"desc": "Toggle in-game tutorial panel"
},
"fps.toggle": {
"name": "Toggle FPS counter",
"desc": "Toggle 'frames per second' counter"
},
"realtime.toggle": {
"name": "Toggle real-time overlay",
"desc": "Toggle current display of computer time"
},
"timeelapsedcounter.toggle": {
"name": "Toggle game-time overlay",
"desc": "Shows the game time elapsed since the game started."
},
"ceasefirecounter.toggle": {
"name": "Toggle ceasefire counter",
"desc": "Toggle ceasefire counter"
},
"session.diplomacycolors": {
"name": "Toggle diplomacy colors",
"desc": "Toggle diplomacy colors"
},
"silhouettes": {
"name": "Toggle unit silhouettes",
"desc": "Toggle unit silhouettes"
},
"session.showstatusbars": {
"name": "Toggle status bars",
"desc": "Toggle display of status bars"
},
"session.highlightguarding": {
"name": "Toggle guarding highlight",
"desc": "Toggle highlight of guarding units"
},
"session.highlightguarded": {
"name": "Toggle guarded highlight",
"desc": "Toggle highlight of guarded units"
},
"session.toggleattackrange": {
"name": "Togge attack ranges",
"desc": "Toggle display of attack range overlays of selected defensive structures"
},
"session.toggleaurasrange": {
"name": "Toggle aura ranges",
"desc": "Toggle display of aura range overlays of selected units and structures"
},
"session.togglehealrange": {
"name": "Toggle heal ranges",
"desc": "Toggle display of heal range overlays of selected units"
},
"session.devcommands.toggle": {
"name": "Toggle dev overlay",
"desc": "Toggle developer commands panel"
},
"session.timewarp.fastforward": {
"name": "Fast-forward (timewarp)",
"desc": "Activate fast-forward mode. Must have activated timewarp."
},
"session.timewarp.rewind": {
"name": "Rewing (timewarp)",
"desc": "Rewind time. Must have activated timewarp."
},
"session.savedgames.delete": {
"name": "Delete saved game",
"desc": "Delete the saved game (in the save/load windows)."
},
"session.savedgames.noconfirmation": {
"name": "Delete without confirmation",
"desc": "Don't ask for confirmation when deleting a saved game."
}
}
}
}
@@ -0,0 +1,176 @@
{
"categories": {
"selection": {
"name": "Selecting Units",
"desc": "Hotkeys relating to modifying unit selection."
}
},
"mapped_hotkeys": {
"selection": {
"selection.cancel": {
"name": "Cancel selection",
"desc": "Un-select all units and cancel building placement"
},
"selection.add": {
"name": "Add to selection",
"desc": "Add units to selection"
},
"selection.militaryonly": {
"name": "Select military only",
"desc": "Add only military units to the selection"
},
"selection.nonmilitaryonly": {
"name": "Select non-military only",
"desc": "Add only non-military units to the selection"
},
"selection.idleonly": {
"name": "Select only idle units",
"desc": "Select only idle units"
},
"selection.woundedonly": {
"name": "Select only wounded units",
"desc": "Select only wounded units"
},
"selection.remove": {
"name": "Remove units from selection",
"desc": "Remove units from selection"
},
"selection.idleworker": {
"name": "Select next idle worker",
"desc": "Select next idle worker"
},
"selection.idlewarrior": {
"name": "Select next idle warrior",
"desc": "Select next idle warrior"
},
"selection.idleunit": {
"name": "Select next idle unit",
"desc": "Select next idle unit"
},
"selection.offscreen": {
"name": "Include offscreen",
"desc": "Include offscreen units in selection"
},
"selection.group.save.0": {
"name": "Set Control Group 0",
"desc": "Save current selection as Control Group 0"
},
"selection.group.save.1": {
"name": "Set Control Group 1",
"desc": "Save current selection as Control Group 1"
},
"selection.group.save.2": {
"name": "Set Control Group 2",
"desc": "Save current selection as Control Group 2"
},
"selection.group.save.3": {
"name": "Set Control Group 3",
"desc": "Save current selection as Control Group 3"
},
"selection.group.save.4": {
"name": "Set Control Group 4",
"desc": "Save current selection as Control Group 4"
},
"selection.group.save.5": {
"name": "Set Control Group 5",
"desc": "Save current selection as Control Group 5"
},
"selection.group.save.6": {
"name": "Set Control Group 6",
"desc": "Save current selection as Control Group 6"
},
"selection.group.save.7": {
"name": "Set Control Group 7",
"desc": "Save current selection as Control Group 7"
},
"selection.group.save.8": {
"name": "Set Control Group 8",
"desc": "Save current selection as Control Group 8"
},
"selection.group.save.9": {
"name": "Set Control Group 9",
"desc": "Save current selection as Control Group 9"
},
"selection.group.select.0": {
"name": "Select Control Group 0",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.1": {
"name": "Select Control Group 1",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.2": {
"name": "Select Control Group 2",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.3": {
"name": "Select Control Group 3",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.4": {
"name": "Select Control Group 4",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.5": {
"name": "Select Control Group 5",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.6": {
"name": "Select Control Group 6",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.7": {
"name": "Select Control Group 7",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.8": {
"name": "Select Control Group 8",
"desc": "Change the current selection to control group 0"
},
"selection.group.select.9": {
"name": "Select Control Group 9",
"desc": "Change the current selection to control group 0"
},
"selection.group.add.0": {
"name": "Add Control Group 0",
"desc": "Add Control Group 0 to the current selection"
},
"selection.group.add.1": {
"name": "Add Control Group 1",
"desc": "Add Control Group 1 to the current selection"
},
"selection.group.add.2": {
"name": "Add Control Group 2",
"desc": "Add Control Group 2 to the current selection"
},
"selection.group.add.3": {
"name": "Add Control Group 3",
"desc": "Add Control Group 3 to the current selection"
},
"selection.group.add.4": {
"name": "Add Control Group 4",
"desc": "Add Control Group 4 to the current selection"
},
"selection.group.add.5": {
"name": "Add Control Group 5",
"desc": "Add Control Group 5 to the current selection"
},
"selection.group.add.6": {
"name": "Add Control Group 6",
"desc": "Add Control Group 6 to the current selection"
},
"selection.group.add.7": {
"name": "Add Control Group 7",
"desc": "Add Control Group 7 to the current selection"
},
"selection.group.add.8": {
"name": "Add Control Group 8",
"desc": "Add Control Group 8 to the current selection"
},
"selection.group.add.9": {
"name": "Add Control Group 9",
"desc": "Add Control Group 9 to the current selection"
}
}
}
}