Skip to content

Keybinds

TaroEld edited this page Mar 8, 2026 · 39 revisions

Description

This system allows a mod to easily add a user-configurable function to be run when a user presses a specific key-combination, or to detect if a certain key-combination is pressed. It works closely with the Mod Settings system to make the keybinds modifiable.

Info

Key Combinations

A key combination is a group of (one or more) keys which will run the keybind function when pressed. Key combinations are handled as a string in the form: "key1+key2+key3" where key1...keyX are the keys that need to be pressed simultaneously for the function to be executed. The number of keys is completely arbitrary, and keys are treated equally - ctrl or shift are treated the same as a or z. Despite the name, two mouse keys can also be bound: leftclick and rightclick. Apart from the advanced Javascript keybinds, mouse and keyboard are treated equally.

Key combinations are usually handled as a group, since any keybind can have any number of key combinations that will call the function in the keybind. These are then passed in the form "keycombination1/keycombination2", where a keycombinationX is a combination of keys as described above.
Thus, a single keybind can have multiple key combinations, each consisting of one or more keys:

  • a: just the key a
  • a+b: a and b simultaneously
  • a+b/c+d: either a and b, or c and d.

Key combinations can be shared within and between mods. So, multiple mods could use the key combination a+b.

Key State

A squirrel keybind can be be called during three distinct points of a 'keypress': When it's first pressed down, while it's pressed down, or when it's released.
Different keybinds can fire for press, continuous, and release of the same key combination, and press is not automatically continuous.

Multiple states can be passed as | separate keys like game states : ::MSU.Key.KeyState.Press | ::MSU.Key.KeyState.Release.

Press

::MSU.Key.KeyState.Press

Will call the keybind when the appropriate key combination is first pressed.

Release

::MSU.Key.KeyState.Release

Will call the keybind when the player releases any key after pressing the key combination. This is the default, and also used by vanilla keybinds.

Continuous

::MSU.Key.KeyState.Continuous

Will call the keybind every frame the key combination is pressed.

Game State

The game has 3 distinct game states, Squirrel keybinds can be set up to be call on any of the game states by passing any combination of the below states separate by a |.

World

::MSU.Key.State.World

This is the state the game is in while the player is on the map.

Tactical

::MSU.Key.State.Tactical

This is the state the game is in during player combat.

Main Menu

::MSU.Key.State.MainMenu

This is the state the game is in while no campaign has been loaded.

All

::MSU.Key.State.All

A convenience key to be used instead of ::MSU.Key.State.World | ::MSU.Key.State.Tactical | ::MSU.Key.State.MainMenu

Keybind

As Squirrel and Javascript handle keys quite differently, MSU implements one type of keybind for each.
In the vast majority of circumstances, a modder should use a Squirrel Keybind which directly calls squirrel code when an appropriate key combination is pressed.
For a Javascript Keybind, while the keybind is defined in squirrel code, the modder mmust themselves implement a method in JS to check if the keybind is actuated. Usually, this takes the form of a keyboard or mouse event listener.

Squirrel Keybind

<Mod>.Keybinds.addSQKeybind( _id, _keyCombinations, _state, _function, _name = null, _keyState = null, _description = "" )
// returns the newly created keybind of class ::MSU.Class.KeybindSQ
// _id, _keyCombinations, _name, _description are strings
// _state is an entry in ::MSU.Key.State
// _function is a function
// _keyState is an entry in ::MSU.Key.KeyState

_id must be unique for all Keybinds and Settings Elements in the mod.
_keyCombinations is the default set of Key Combinations that the keybind will be usable with
_state is a Game State
_name is an optional user facing name that defaults to _id and will be used to generate a keybind setting.
_function is the function that will be called when the keybind is pressed. In the function this will be whatever state the game is currently in.
Return true to interrupt any following keybinds from firing.
Note that the keybinds are executed in order of insertion. This means that, for example, vanilla keybinds will fire before custom keybinds.
_keyState is a Key State, defaults to ::MSU.Key.KeyState.Release
_description is the description for the mod setting that will be generated

Adds a Squirrel keybind that will call _function when any key combination in _keyCombinations is in the correct _keyState and the game is in the game state _state.

Squirrel Passive Keybind

<Mod>.Keybinds.addPassiveKeybind( _id, _keyCombinations, _name = null, _description = "")

Refer to Squirrel Keybind for a description of the arguments.

This simple version of the squirrel keybind does not accept a function and thus does nothing on its own. Its purpose is to be used with isKeybindPressed to check if it is actuated.

JavaScript Keybind

<Mod>.Keybinds.addJSKeybind( _id, _keyCombinations, _name = null, _description = "" )
// returns the newly created keybind of class ::MSU.Class.KeybindJS

Refer to Squirrel Keybind for a description of the arguments.

Adds a Javascript 'keybind' in that it allows javascript code to check if any of the key combinations are pressed by checking

// if the final key being pressed is a mouse button or
MSU.Keybinds.isMousebindPressed(_modID, _id, _event)
// if the final key being pressed is a key.
MSU.Keybinds.isKeybindPressed(_modID, _id, _event)

// _modID, _id are strings
// _event is the event passed to an eventlistener

_modID is the id of your mod passed to MSU
_id is the id of the keybind
These function should be called inside an eventListener, and therefore _event is the parameter that such a callback should have as described on the MDN Web Docs.

JS keybinds/mousebinds are rare, but allow things like interactions with UI elements on button click.
See the second example.
For pure keybinds, you will need to add a keydown / up / press event handler. They only work on elements that are focus-able and currently in focus. A workaround can be a document - level keyhandler. See the third example

Modsettings Menu

Once a keybind is added to a mod, a new Keybinds mod settings page will be added to the Mod Settings screen of that mod.
Each keybind gets an entry, where the user can customize the binding.

Add a Divider

<Mod>.Keybinds.addDivider( _id )
// _id is a string

_id must be unique for all Keybinds and Settings Elements in the mod.\

Adds a Settings Divider to the keybinds page in the mod's mod settings to allow for better organization of keybinds.

Add a Title

<Mod>.Keybinds.addTitle( _id, _name )
// _id and _name are strings

_id must be unique for all Keybinds and Settings Elements in the mod.
_name will be displayed as the title.

Adds a Settings Title to the keybinds page in the mod's mod settings to allow for better organization of keybinds.

Vanilla Keybinds

MSU overrides the default vanilla keyhandling system and re-implements all its original bindings as MSU keybinds. They can be found in the file vanilla_keybinds.
**Note **that the vanilla escape keybind will pop the MenuStack of the respective state (see world_state | tactical_state | main_menu_state :: m.MenuStack). It can thus be unnecessary or even pointless to add an escape keybind. Instead, a MenuStack event should be added in show(), for example:

// my_screen.nut inherits scripts/mods/msu/ui_screen
	function show()
	{
		if (this.m.JSHandle != null && !this.isVisible())
		{
			this.Tooltip.hide();
			this.World.State.m.MenuStack.push(function ()
			{
				::MyMod.MyScreen.hide();
			});
			this.m.JSHandle.asyncCall("show");
		}
	}

Miscellaneous

getKeybind

<Mod>.Keybinds.getKeybind( _id )
// _id is a string

Returns the keybind object of your mod with the id _id.

getKeyCombinations

<keybind>.getKeyCombinations()

Returns the key combinations of this keybind as a string e.g. "h / k".

Bypass key input denial

<keybind>.setBypassInputDenied( _bool )

By default, MSU SQ keybinds do not trigger when a JS input or textarea element is focused.
The point of this is to avoid the keybind triggering while the user is typing in something like a name setter text element.
This behavior can be enabled or disabled for individual SQ keys with the member setBypassInputDenied. The corresponding property BypassInputDenied is initialized to false.

Key input denial can be entirely disabled with the MSU mod setting with the ID blockSQInput, found under the General page.
This should only be done in extreme cases and should be seen as a failsave or debugging tool.

Update Keybind Key Combination

<Mod>.Keybinds.update( _id, _keyCombinations )
// _id and _keycombinations are strings

_id is the id of the keybind to update
_keyCombinations is the a set of key combinations

Changes the key combinations used for the Keybind to _keyCombinations

Check Key Combination Status

<Mod>.Keybinds.isKeybindPressed(_id)
// _id is a string

_id is the id of the keybind to check\

Returns true if the Keybind with _id is currently being held down, false otherwise.

Turn on Debug

Enable the keybindsLog setting in the MSU modsettings to log a variety of debug messages, such as the pressed key and the final key combination.

Examples

Basic squirrel keybind:

// Create a mod
local myMod = ::MSU.Class.Mod("myID", "1.0.0", "Pretty Name");
// add a keybind that prints "hi" when shift+a are 'released' in either main menu or world state:
myMod.Keybinds.addSQKeybind("printHi", "shift+a", ::MSU.Key.State.MainMenu | ::MSU.Key.State.World, function()
{
    ::logInfo("hi");
}, "Print Hi");
// make ctrl+x an available key combination for the keybind
myMod.Keybinds.update("printHi", "ctrl+x/shift+a");
// add a keybind that prints "bye" when escape is pressed (not released):
myMod.Keybinds.addSQKeybind("printBye", "escape", ::MSU.Key.State.MainMenu | ::MSU.Key.State.World, function()
{
    ::logInfo("bye");
}, "Print Bye", ::MSU.Key.KeyState.Press);

Basic JS keybind:

myMod.Keybinds.addJSKeybind("rightclick", "shift+rightclick", "My Event", "Key combination will fire on shift.rightclick");
myElement.mousedown(function (event)
{
  var isPressed = MSU.Keybinds.isMousebindPressed(MyMod.ID, "rightclick", _event);
  if (isPressed) console.error("Hello, world!");
});

Keyboard JS keybind, using document - level event handler. Remember to remove those if you no longer need them, for example during your hide() function.

$(document).on('keydown.my-name-space', function(_event){
  var isPressed = MSU.Keybinds.isKeybindPressed(MyMod.ID, "mykeybind", _event);
  if (isPressed) console.error("Hello, world!");
})

Key Reference

The values for the tables below are what a key combination can use separated by + characters

    MouseMapSQ = {
        "1" : "leftclick",
        "2" : "rightclick",
    },
    KeyMapSQ = {
        "1" : "1",
        "2" : "2",
        "3" : "3",
        "4" : "4",
        "5" : "5",
        "6" : "6",
        "7" : "7",
        "8" : "8",
        "9" : "9",
        "10" : "0",
        "11" : "a",
        "12" : "b",
        "13" : "c",
        "14" : "d",
        "15" : "e",
        "16" : "f",
        "17" : "g",
        "18" : "h",
        "19" : "i",
        "20" : "j",
        "21" : "k",
        "22" : "l",
        "23" : "m",
        "24" : "n",
        "25" : "o",
        "26" : "p",
        "27" : "q",
        "28" : "r",
        "29" : "s",
        "30" : "t",
        "31" : "u",
        "32" : "v",
        "33" : "w",
        "34" : "x",
        "35" : "y",
        "36" : "z",
        "37" : "backspace",
        "38" : "tab",
        "39" : "enter",
        "40" : "space",
        "41" : "escape",
        "44" : "end",
        "45" : "home",
        "46" : "pagedown",
        "47" : "pageup",
        "48" : "left",
        "49" : "up",
        "50" : "right",
        "51" : "down",
        "53" : "insert",
        "54" : "delete",
        "55" : "n0", // numpad keys
        "56" : "n1",
        "57" : "n2",
        "58" : "n3",
        "59" : "n4",
        "60" : "n5",
        "61" : "n6",
        "62" : "n7",
        "63" : "n8",
        "64" : "n9",
/*
        While technically present, these keys are unreliable
        "66" : "*",
        "67" : "+",
        "68" : "-",
        "70" : "/",
*/
        "71" : "f1",
        "72" : "f2",
        "73" : "f3",
        "74" : "f4",
        "75" : "f5",
        "76" : "f6",
        "77" : "f7",
        "78" : "f8",
        "79" : "f9",
        "80" : "f10",
        "81" : "f11",
        "82" : "f12",
        "83" : "f13",
        "84" : "f14",
        "85" : "f15",
        "86" : "f16",
        "87" : "f17",
        "88" : "f18",
        "89" : "f19",
        "90" : "f20",
        "91" : "f21",
        "92" : "f22",
        "93" : "f23",
        "94" : "f24",
        "95" : "ctrl",
        "96" : "shift",
        "97" : "alt"
    }

Clone this wiki locally