{"name":"Arma 3: Modded Keybinding","title":"Arma 3: Modded Keybinding","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Modded_Keybinding","revid":363526,"updated":"2024-04-03T19:34:02Z","aliases":[],"markdown":"As of Arma 3 v2.06, mods are able to define keys that can be bound by the user in the keybindings.\n\n```cpp\nclass CfgUserActions\n{\n    class TAG_MyActionName // This class name is used for internal representation and also for the inputAction command.\n    {\n        displayName = \"\";\n        tooltip = \"\";\n        onActivate = \"['TAG_MyActionName', true] call TAG_fnc_MyHandler\";        // _this is always true.\n        onDeactivate = \"['TAG_MyActionName', false] call TAG_fnc_MyHandler\";    // _this is always false.\n        onAnalog = \"['TAG_MyActionName', _this] call TAG_fnc_MyAnalogHandler\";    // _this is the scalar analog value.\n        analogChangeThreshold = 0.01; // Minimum change required to trigger the onAnalog EH (default: 0.01).\n        modifierBlocking = 1; // Whether this action would block other actions if the assigned key has modifier keys on it. (Since Arma 2.12)\n    };\n};\n```\n\n### Key Combination Enumerations\n\n```cpp\n// Secondary combo types:\n#define INPUT_DEVICE_COMBO_KB 0x00100000 // Keyboard button (key)\n#define INPUT_DEVICE_COMBO_MB 0x00300000 // Mouse button\n#define INPUT_DEVICE_COMBO_JB 0x00500000 // Joystick button\n#define INPUT_DEVICE_COMBO_JP 0x00600000 // Joystick POV\n#define INPUT_DEVICE_COMBO_XI 0x00900000 // Xbox controller (XInput)\n\n// Main combo types:\n#define INPUT_DEVICE_MAIN_MB 0x00010000 // Mouse button\n#define INPUT_DEVICE_MAIN_MA 0x00020000 // Mouse axis\n#define INPUT_DEVICE_MAIN_KB 0x00030000 // Keyboard button (key)\n#define INPUT_DEVICE_MAIN_JB 0x00040000 // Joystick button\n#define INPUT_DEVICE_MAIN_JA 0x00050000 // Joystick axis\n#define INPUT_DEVICE_MAIN_JP 0x00060000 // Joystick POV\n#define INPUT_DEVICE_MAIN_XI 0x00070000 // Xbox controller (XInput)\n#define INPUT_DEVICE_MAIN_TR 0x00080000 // Movement tracking device\n\n// Device types:\n#define INPUT_DEVICE_SOLO_KB 0x00000000 // Keyboard button (key)\n#define INPUT_DEVICE_SOLO_MB 0x00010000 // Mouse button\n#define INPUT_DEVICE_SOLO_JB 0x00020000 // Stick button\n#define INPUT_DEVICE_SOLO_JA 0x00030000 // Stick axis\n#define INPUT_DEVICE_SOLO_JP 0x00040000 // Stick POV\n#define INPUT_DEVICE_SOLO_XI 0x00050000 // XInput device\n#define INPUT_DEVICE_SOLO_TR 0x00080000 // EyeXTracker, TrackIR, FreeTrack, ... exclusive, in this preference\n#define INPUT_DEVICE_SOLO_MA 0x00100000 // Mouse axis\n```\n\n```cpp\nenum MouseButtons\n{\n    MOUSE_BUTTONS_LEFT        = 0,\n    MOUSE_BUTTONS_RIGHT        = 1,\n    MOUSE_BUTTONS_MIDDLE    = 2,\n    MOUSE_BUTTONS_CUSTOM_1    = 3,\n    MOUSE_BUTTONS_CUSTOM_2    = 4,\n    MOUSE_BUTTONS_CUSTOM_3    = 5,\n    MOUSE_BUTTONS_CUSTOM_4    = 6,\n    MOUSE_BUTTONS_CUSTOM_5    = 7\n};\n\n#define INPUT_DOUBLE_TAP_OFFSET        0x100    // Offset for double click (used as mask)\n#define MOUSE_CLICK_OFFSET            0x80    // Offset for mouse button click (compared to hold)\n```\n\nExamples:\n\n- Left click: 0x80\n- Left click hold: 0x0\n- Left click doubletap: 0x100\n- Right click hold: 0x1\n\nThere are 256 stick buttons.\n\n```cpp\n#define N_JOYSTICK_AXES        8 // 3 normal, 3 rotate, 2 sliders\n#define N_JOYSTICK_POV        8 // 8 directional stick\n```\n\nTrackIR axis:\n\n```cpp\nenum MovementTrackerAxis\n{\n    TRACK_PITCH = 0,    // Up / down rotation\n    TRACK_YAW = 1,        // Left / right rotation\n    TRACK_ROLL = 2,        // Side roll\n    TRACK_X = 3,        // Left / right move\n    TRACK_Y = 4,        // Up / down move\n    TRACK_Z = 5            // Forward / backward move\n};\n```\n\n```cpp\nenum MouseAxis\n{\n    MOUSE_AXIS_LEFT = 0,\n    MOUSE_AXIS_RIGHT = 1,\n    MOUSE_AXIS_UP = 2,\n    MOUSE_AXIS_DOWN = 3, // Last actual mouse axis, change N_MOUSE_AXES if adding new axis\n    MOUSE_AXIS_WHEEL_UP = 4,\n    MOUSE_AXIS_WHEEL_DOWN = 5\n};\n```\n\n### Adding a new key\n\n#### Defining a new action in CfgUserActions\n\n```cpp\nclass CfgUserActions\n{\n    class TAG_MyActionName // This class name is used for internal representation and also for the inputAction command.\n    {\n        displayName = \"My Test Action\";\n        tooltip = \"This action is for testing.\";\n        onActivate = \"_this call TAG_fnc_MyHandler\";        // _this is always true.\n        onDeactivate = \"_this call TAG_fnc_MyHandler\";        // _this is always false.\n        onAnalog = \"_this call TAG_fnc_MyAnalogHandler\";    // _this is the scalar analog value.\n        analogChangeThreshold = 0.1; // Minimum change required to trigger the onAnalog EH (default: 0.01).\n    };\n};\n```\n\n#### Defining a default keybind in CfgDefaultKeysPresets\n\n```cpp\nclass CfgDefaultKeysPresets\n{\n    class Arma2 // Arma2 is inherited by all other presets.\n    {\n        class Mappings\n        {\n            TAG_MyActionName[] = {\n                0x25, // DIK_K\n                \"256 + 0x25\", // 256 is the bitflag for \"doubletap\", 0x25 is the DIK code for K.\n                \"0x00010000 + 2\" // 0x00010000 is the bitflag for \"mouse button\".\n            };\n        };\n    };\n};\n```\n\n> [!WARNING]\n> If the key code is large enough, for example `0x1D130023` (<kbd>Ctrl</kbd> + <kbd>H</kbd>), then adding values may lead to a wrong result due to rounding errors (see Number - Floating-point Precision).\n> As such, it is recommended to do the calculation manually and use that value instead.\n\n#### Adding a keybind to the keybind options dialog\n\n```cpp\nclass UserActionGroups\n{\n    class ModSection // Unique classname of your category.\n    {\n        name = \"Mod Section\"; // Display name of your category.\n        isAddon = 1;\n        group[] = { \"TAG_MyActionName\" }; // List of all actions inside this category.\n    };\n};\n```\n\n#### Setting up a collision group (optional)\n\nClass UserActionsConflictGroups provides the ability to configure checks for keybinding collisions. The following example demonstrates how to ensure that the input does not conflict with car movement keybindings:\n\n```cpp\nclass UserActionsConflictGroups\n{\n    class ActionGroups\n    {\n        TAG_MyActionGroup[] = { \"TAG_MyActionName\" };\n    };\n\n    class CollisionGroups\n    {\n        // Add your group to an existing collision group:\n        carMove[] += { \"TAG_MyActionGroup\" };\n\n        // Or alternatively add your own collision group (which is usually preferrable):\n        TAG_MyActionGroupCollisions[] = { \"basic\", \"vehBasic\", \"HeadMove\", \"TAG_MyActionGroup\" };\n    };\n};\n```\n\n### Scripted Event Handlers\n\n```sqf\naddUserActionEventHandler [\"ReloadMagazine\", \"Activate\", {\n    systemChat \"Reloading!\";\n    removeUserActionEventHandler [\"ReloadMagazine\", \"Activate\", _thisEventHandler];\n}];\n```\n\nThe persistence of these EHs is the same as that of Mission Event Handlers - they are scoped per mission and get removed when the mission ends.\n\n**See Also:**\n\n- addUserActionEventHandler\n- removeUserActionEventHandler\n- removeAllUserActionEventHandlers\n\n### Additional documentation on key bitflags (CfgDefaultKeysPresets)\n\n> [!NOTE]\n> - See also DIK KeyCodes\n> - The format is as follows (here for <kbd>Ctrl</kbd> + <kbd>W</kbd> with a value of `487784465`, hexadecimal `0x1D130011`):\n>\n> |  |  |  |  |  |  |\n> |---|---|---|---|---|---|\n> | Value | 0x | 1D | 13 | 00 | 11 |\n> | Title | hexPrefix | comboKB | deviceType | doubleTapInfo | keyId |\n> | Translated | N/A | `DIK_LCONTROL` | `INPUT_DEVICE_COMBO_KB` + `INPUT_DEVICE_MAIN_KB` | 0 | DIK_W |\n> | Details | N/A | combo keyboard key (second key of a combo is always keyboard) | device type of first key (joystick, mouse, KB, ...)<br>or in case of combo, first half secondary combo type, second half main combo type | offset for joysticks or double tap info for keyboard | key/button/axis identification |\n\n```sqf\n// dik = 0xAABBCCDD\n// BBCCDD = whole info about first key\n// CCDD = button info (doubleTap or joyID + btnID)\n// DD = button local ID\n```\n\n**Example for <kbd>A</kbd> + <kbd>2×B</kbd>**\n\n```\nDIK_A = 0x1E, DIK_B = 0x30\nCombined code = 0x1E130130\n```\n\ncombo key is DIK_A (1E), combo key device type is INPUT_DEVICE_COMBO_KB (1), main key device type is INPUT_DEVICE_MAIN_KB (3), doubletap (01), main key is IDK_B (30)\n\n**Example for <kbd>A</kbd> + Middle Mouse Button**\n\n```\nDIK_A = 0x1E, middle mouse hold = 0x2\nCombined code 0x1E110002\n```\n\nCombo key is DIK_A (1E), combo key device type is INPUT_DEVICE_COMBO_KB (1), main key device is INPUT_DEVICE_MAIN_MB (1), no double tap (00), main key is MOUSE_BUTTONS_MIDDLE (2)\n\n**Example for A + Mouse Left (move)**\n\n```\nDIK_A = 0x1E, MOUSE_AXIS_LEFT = 0\nCombined code 0x1E120001\n```\n\nCombo key is DIK_A (1E), combo key device type is INPUT_DEVICE_COMBO_KB (1), main key device is INPUT_DEVICE_MAIN_MA (2), no double tap (00), main key is MOUSE_AXIS_RIGHT (1)\n\n**Example for Left Mouse Button + Middle Mouse Button**\n\n```\nMOUSE_BUTTONS_LEFT = 0, MOUSE_BUTTONS_MIDDLE = 2\nCombined code 0x02310000\n```\n\nCombo key is MOUSE_BUTTONS_MIDDLE (2), combo key device type is INPUT_DEVICE_COMBO_MB (3), main key device is INPUT_DEVICE_MAIN_MB (1), no double tap (00), main key is MOUSE_BUTTONS_LEFT (0)","sections":[{"heading":null,"level":1,"markdown":"As of Arma 3 v2.06, mods are able to define keys that can be bound by the user in the keybindings.\n\n```cpp\nclass CfgUserActions\n{\n    class TAG_MyActionName // This class name is used for internal representation and also for the inputAction command.\n    {\n        displayName = \"\";\n        tooltip = \"\";\n        onActivate = \"['TAG_MyActionName', true] call TAG_fnc_MyHandler\";        // _this is always true.\n        onDeactivate = \"['TAG_MyActionName', false] call TAG_fnc_MyHandler\";    // _this is always false.\n        onAnalog = \"['TAG_MyActionName', _this] call TAG_fnc_MyAnalogHandler\";    // _this is the scalar analog value.\n        analogChangeThreshold = 0.01; // Minimum change required to trigger the onAnalog EH (default: 0.01).\n        modifierBlocking = 1; // Whether this action would block other actions if the assigned key has modifier keys on it. (Since Arma 2.12)\n    };\n};\n```"},{"heading":"Key Combination Enumerations","level":3,"markdown":"```cpp\n// Secondary combo types:\n#define INPUT_DEVICE_COMBO_KB 0x00100000 // Keyboard button (key)\n#define INPUT_DEVICE_COMBO_MB 0x00300000 // Mouse button\n#define INPUT_DEVICE_COMBO_JB 0x00500000 // Joystick button\n#define INPUT_DEVICE_COMBO_JP 0x00600000 // Joystick POV\n#define INPUT_DEVICE_COMBO_XI 0x00900000 // Xbox controller (XInput)\n\n// Main combo types:\n#define INPUT_DEVICE_MAIN_MB 0x00010000 // Mouse button\n#define INPUT_DEVICE_MAIN_MA 0x00020000 // Mouse axis\n#define INPUT_DEVICE_MAIN_KB 0x00030000 // Keyboard button (key)\n#define INPUT_DEVICE_MAIN_JB 0x00040000 // Joystick button\n#define INPUT_DEVICE_MAIN_JA 0x00050000 // Joystick axis\n#define INPUT_DEVICE_MAIN_JP 0x00060000 // Joystick POV\n#define INPUT_DEVICE_MAIN_XI 0x00070000 // Xbox controller (XInput)\n#define INPUT_DEVICE_MAIN_TR 0x00080000 // Movement tracking device\n\n// Device types:\n#define INPUT_DEVICE_SOLO_KB 0x00000000 // Keyboard button (key)\n#define INPUT_DEVICE_SOLO_MB 0x00010000 // Mouse button\n#define INPUT_DEVICE_SOLO_JB 0x00020000 // Stick button\n#define INPUT_DEVICE_SOLO_JA 0x00030000 // Stick axis\n#define INPUT_DEVICE_SOLO_JP 0x00040000 // Stick POV\n#define INPUT_DEVICE_SOLO_XI 0x00050000 // XInput device\n#define INPUT_DEVICE_SOLO_TR 0x00080000 // EyeXTracker, TrackIR, FreeTrack, ... exclusive, in this preference\n#define INPUT_DEVICE_SOLO_MA 0x00100000 // Mouse axis\n```\n\n```cpp\nenum MouseButtons\n{\n    MOUSE_BUTTONS_LEFT        = 0,\n    MOUSE_BUTTONS_RIGHT        = 1,\n    MOUSE_BUTTONS_MIDDLE    = 2,\n    MOUSE_BUTTONS_CUSTOM_1    = 3,\n    MOUSE_BUTTONS_CUSTOM_2    = 4,\n    MOUSE_BUTTONS_CUSTOM_3    = 5,\n    MOUSE_BUTTONS_CUSTOM_4    = 6,\n    MOUSE_BUTTONS_CUSTOM_5    = 7\n};\n\n#define INPUT_DOUBLE_TAP_OFFSET        0x100    // Offset for double click (used as mask)\n#define MOUSE_CLICK_OFFSET            0x80    // Offset for mouse button click (compared to hold)\n```\n\nExamples:\n\n- Left click: 0x80\n- Left click hold: 0x0\n- Left click doubletap: 0x100\n- Right click hold: 0x1\n\nThere are 256 stick buttons.\n\n```cpp\n#define N_JOYSTICK_AXES        8 // 3 normal, 3 rotate, 2 sliders\n#define N_JOYSTICK_POV        8 // 8 directional stick\n```\n\nTrackIR axis:\n\n```cpp\nenum MovementTrackerAxis\n{\n    TRACK_PITCH = 0,    // Up / down rotation\n    TRACK_YAW = 1,        // Left / right rotation\n    TRACK_ROLL = 2,        // Side roll\n    TRACK_X = 3,        // Left / right move\n    TRACK_Y = 4,        // Up / down move\n    TRACK_Z = 5            // Forward / backward move\n};\n```\n\n```cpp\nenum MouseAxis\n{\n    MOUSE_AXIS_LEFT = 0,\n    MOUSE_AXIS_RIGHT = 1,\n    MOUSE_AXIS_UP = 2,\n    MOUSE_AXIS_DOWN = 3, // Last actual mouse axis, change N_MOUSE_AXES if adding new axis\n    MOUSE_AXIS_WHEEL_UP = 4,\n    MOUSE_AXIS_WHEEL_DOWN = 5\n};\n```"},{"heading":"Adding a new key","level":3,"markdown":""},{"heading":"Defining a new action in CfgUserActions","level":4,"markdown":"```cpp\nclass CfgUserActions\n{\n    class TAG_MyActionName // This class name is used for internal representation and also for the inputAction command.\n    {\n        displayName = \"My Test Action\";\n        tooltip = \"This action is for testing.\";\n        onActivate = \"_this call TAG_fnc_MyHandler\";        // _this is always true.\n        onDeactivate = \"_this call TAG_fnc_MyHandler\";        // _this is always false.\n        onAnalog = \"_this call TAG_fnc_MyAnalogHandler\";    // _this is the scalar analog value.\n        analogChangeThreshold = 0.1; // Minimum change required to trigger the onAnalog EH (default: 0.01).\n    };\n};\n```"},{"heading":"Defining a default keybind in CfgDefaultKeysPresets","level":4,"markdown":"```cpp\nclass CfgDefaultKeysPresets\n{\n    class Arma2 // Arma2 is inherited by all other presets.\n    {\n        class Mappings\n        {\n            TAG_MyActionName[] = {\n                0x25, // DIK_K\n                \"256 + 0x25\", // 256 is the bitflag for \"doubletap\", 0x25 is the DIK code for K.\n                \"0x00010000 + 2\" // 0x00010000 is the bitflag for \"mouse button\".\n            };\n        };\n    };\n};\n```\n\n> [!WARNING]\n> If the key code is large enough, for example `0x1D130023` (<kbd>Ctrl</kbd> + <kbd>H</kbd>), then adding values may lead to a wrong result due to rounding errors (see Number - Floating-point Precision).\n> As such, it is recommended to do the calculation manually and use that value instead."},{"heading":"Adding a keybind to the keybind options dialog","level":4,"markdown":"```cpp\nclass UserActionGroups\n{\n    class ModSection // Unique classname of your category.\n    {\n        name = \"Mod Section\"; // Display name of your category.\n        isAddon = 1;\n        group[] = { \"TAG_MyActionName\" }; // List of all actions inside this category.\n    };\n};\n```"},{"heading":"Setting up a collision group (optional)","level":4,"markdown":"Class UserActionsConflictGroups provides the ability to configure checks for keybinding collisions. The following example demonstrates how to ensure that the input does not conflict with car movement keybindings:\n\n```cpp\nclass UserActionsConflictGroups\n{\n    class ActionGroups\n    {\n        TAG_MyActionGroup[] = { \"TAG_MyActionName\" };\n    };\n\n    class CollisionGroups\n    {\n        // Add your group to an existing collision group:\n        carMove[] += { \"TAG_MyActionGroup\" };\n\n        // Or alternatively add your own collision group (which is usually preferrable):\n        TAG_MyActionGroupCollisions[] = { \"basic\", \"vehBasic\", \"HeadMove\", \"TAG_MyActionGroup\" };\n    };\n};\n```"},{"heading":"Scripted Event Handlers","level":3,"markdown":"```sqf\naddUserActionEventHandler [\"ReloadMagazine\", \"Activate\", {\n    systemChat \"Reloading!\";\n    removeUserActionEventHandler [\"ReloadMagazine\", \"Activate\", _thisEventHandler];\n}];\n```\n\nThe persistence of these EHs is the same as that of Mission Event Handlers - they are scoped per mission and get removed when the mission ends.\n\n**See Also:**\n\n- addUserActionEventHandler\n- removeUserActionEventHandler\n- removeAllUserActionEventHandlers"},{"heading":"Additional documentation on key bitflags (CfgDefaultKeysPresets)","level":3,"markdown":"> [!NOTE]\n> - See also DIK KeyCodes\n> - The format is as follows (here for <kbd>Ctrl</kbd> + <kbd>W</kbd> with a value of `487784465`, hexadecimal `0x1D130011`):\n>\n> |  |  |  |  |  |  |\n> |---|---|---|---|---|---|\n> | Value | 0x | 1D | 13 | 00 | 11 |\n> | Title | hexPrefix | comboKB | deviceType | doubleTapInfo | keyId |\n> | Translated | N/A | `DIK_LCONTROL` | `INPUT_DEVICE_COMBO_KB` + `INPUT_DEVICE_MAIN_KB` | 0 | DIK_W |\n> | Details | N/A | combo keyboard key (second key of a combo is always keyboard) | device type of first key (joystick, mouse, KB, ...)<br>or in case of combo, first half secondary combo type, second half main combo type | offset for joysticks or double tap info for keyboard | key/button/axis identification |\n\n```sqf\n// dik = 0xAABBCCDD\n// BBCCDD = whole info about first key\n// CCDD = button info (doubleTap or joyID + btnID)\n// DD = button local ID\n```\n\n**Example for <kbd>A</kbd> + <kbd>2×B</kbd>**\n\n```\nDIK_A = 0x1E, DIK_B = 0x30\nCombined code = 0x1E130130\n```\n\ncombo key is DIK_A (1E), combo key device type is INPUT_DEVICE_COMBO_KB (1), main key device type is INPUT_DEVICE_MAIN_KB (3), doubletap (01), main key is IDK_B (30)\n\n**Example for <kbd>A</kbd> + Middle Mouse Button**\n\n```\nDIK_A = 0x1E, middle mouse hold = 0x2\nCombined code 0x1E110002\n```\n\nCombo key is DIK_A (1E), combo key device type is INPUT_DEVICE_COMBO_KB (1), main key device is INPUT_DEVICE_MAIN_MB (1), no double tap (00), main key is MOUSE_BUTTONS_MIDDLE (2)\n\n**Example for A + Mouse Left (move)**\n\n```\nDIK_A = 0x1E, MOUSE_AXIS_LEFT = 0\nCombined code 0x1E120001\n```\n\nCombo key is DIK_A (1E), combo key device type is INPUT_DEVICE_COMBO_KB (1), main key device is INPUT_DEVICE_MAIN_MA (2), no double tap (00), main key is MOUSE_AXIS_RIGHT (1)\n\n**Example for Left Mouse Button + Middle Mouse Button**\n\n```\nMOUSE_BUTTONS_LEFT = 0, MOUSE_BUTTONS_MIDDLE = 2\nCombined code 0x02310000\n```\n\nCombo key is MOUSE_BUTTONS_MIDDLE (2), combo key device type is INPUT_DEVICE_COMBO_MB (3), main key device is INPUT_DEVICE_MAIN_MB (1), no double tap (00), main key is MOUSE_BUTTONS_LEFT (0)"}],"categories":["Arma 3: Editing","Introduced with Arma 3 version 2.06"],"groups":["General"]}