Controller modding guide / FAQ
Posted: Wed Jun 14, 2023 7:23 pm
Factorio 1.1.83 has added support for game controllers to the PC version of the game. Naturally, this new control scheme may cause issues with mods, so this guide is intended to help ease the process of adapting mods to support controllers if needed.
I'm a mod author, what does this mean for me?
For the vast majority of mods, nothing! Controller support is written in such a way that it works with most mods out of the box. However, while mods may function, they may not be very convenient to use, especially if they have custom GUIs.
How does this affect existing input bindings?
Game controller input bindings are kept separately from keyboard/mouse bindings, so existing bindings will not be affected. Furthermore, changes made to one input method's bindings will not affect the other. Mods with custom-inputs will need to define defaults for each input method separately.
How do I assign default controller bindings to custom-inputs?
custom-input has gained two new properties: controller_key_sequence and controller_alt_key_sequence. Formatting-wise these work identically to key_sequence and alt_key_sequence.
Controllers use different button names from keyboard/mouse. For convenience, here is a diagram of controller buttons to their respective internal names. Binding a custom-input to a button is as simple as using that button's internal name:
A note about setting default bindings
Due to the severely limited number of buttons and possible combos on a game controller, it is highly recommended that most custom-inputs do not receive default controller bindings. If there is functionality that is only accessible via custom-input, it is recommended to add an alternate way to invoke that functionality, i.e. with a shortcut in the quick panel.
If a custom-input is contextual and/or is replicating an existing binding (i.e. mouse-button-1) for specific circumstances, then giving it a default binding is OK.
Face buttons
The game includes two settings related to the four "face buttons" on a controller:
Combo bindings
controller-lefttrigger and controller-righttrigger may be used as modifiers to form combo bindings. These are the only two buttons that can be used as modifiers - for example, it is impossible to make a combo using multiple face buttons. To create a combo, use the button + button syntax as normal:
Localisation
The game's locale system provides a handful of macros to display control inputs. You can find a list of these macros on the wiki. Using these macros in locale will automatically choose the correct representation for the input method that you are using.
For example, this stone furnace description:
will show in-game as
Reading and reacting to changes in input method
The LuaPlayer::input_method read contains the player's current input method, as a variant of defines.input_method. The on_player_input_method_changed event will be called whenever a player changes their input method.
LuaPlayer::input_method will only be accurate during and after on_player_input_method_changed; reading LuaPlayer::input_method during on_player_created or on_player_joined_game is unreliable. When a player is created, their input method will always initially be keyboard_and_mouse, and if they are using a controller, on_player_input_method_changed will be called later. Always assume that a new player is using a keyboard and mouse, and only activate controller-specific behavior during on_player_input_method_changed.
Quick panel - shortcut bar
When using a controller, the standard hotbar and shortcut bar are replaced by the quick panel. The "tools" tab of the quick panel contains the shortcut bar buttons:
The shortcuts in this quick panel are not able to be rearranged by the user. The quick panel logic will arrange the shortcuts based on their prototype order. It is very strongly recommended that mods order their shortcuts to be after all of the vanilla shortcuts, as to not hurt muscle memory for vanilla tools.
Vanilla shortcut order strings
Mod GUIs
The game includes a heuristic to select GUI elements in the currently opened GUI. For modded GUIs, this heuristic will only apply to a window if it is currently contained in LuaPlayer::opened. If a mod GUI is not set to opened, the player has to use free-cursor mode to interact with it. It is recommended that this be avoided whenever is reasonable.
Click modifiers and mouse buttons
For the purposes of GUI events, the following mappings are made:
As a potential workaround for the reduced capabilities, 1.1.83 has also added cursor_display_location to on_gui_click and custom input events. This property gives the current location of the mouse cursor on the user's screen. This can be used to create a context menu where the various actions can be contained. Keep in mind that for the controller heuristic to focus the context menu, it needs to be set as LuaPlayer::opened.
Game controller interaction modes
The game's heuristic uses the element type and a combination of other factors to determine if it should be selected by a controller. However, the heuristic may not perform as expected on modded GUIs, especially if a lot of GUI tricks or hacks are in use. Writing LuaGuiElement::game_controller_interaction will modify the heuristic's behavior for the given element.
Convenience bindings
It is notably more cumbersome to navigate a GUI with a controller than with a mouse. Because of this, it is recommended to add optional custom-inputs to speed up GUI interaction. For example, if a GUI has multiple tabs, adding optional bindings to switch tabs without having to navigate to and click them would be beneficial. Take care to only listen for these bindings if the GUI is actively opened, to avoid conflicts with other mods.
I'm a mod author, what does this mean for me?
For the vast majority of mods, nothing! Controller support is written in such a way that it works with most mods out of the box. However, while mods may function, they may not be very convenient to use, especially if they have custom GUIs.
How does this affect existing input bindings?
Game controller input bindings are kept separately from keyboard/mouse bindings, so existing bindings will not be affected. Furthermore, changes made to one input method's bindings will not affect the other. Mods with custom-inputs will need to define defaults for each input method separately.
How do I assign default controller bindings to custom-inputs?
custom-input has gained two new properties: controller_key_sequence and controller_alt_key_sequence. Formatting-wise these work identically to key_sequence and alt_key_sequence.
Controllers use different button names from keyboard/mouse. For convenience, here is a diagram of controller buttons to their respective internal names. Binding a custom-input to a button is as simple as using that button's internal name:
Code: Select all
controller_key_sequence = "controller-y"
Due to the severely limited number of buttons and possible combos on a game controller, it is highly recommended that most custom-inputs do not receive default controller bindings. If there is functionality that is only accessible via custom-input, it is recommended to add an alternate way to invoke that functionality, i.e. with a shortcut in the quick panel.
If a custom-input is contextual and/or is replicating an existing binding (i.e. mouse-button-1) for specific circumstances, then giving it a default binding is OK.
Face buttons
The game includes two settings related to the four "face buttons" on a controller:
- Icons: Choose how the buttons are represented in the GUI.
- Button layout: Choose which buttons are interpreted as controller-a and controller-b.
- Western: controller-a on bottom, controller-b on right.
- Eastern: controller-a on right, controller-b on bottom.
Combo bindings
controller-lefttrigger and controller-righttrigger may be used as modifiers to form combo bindings. These are the only two buttons that can be used as modifiers - for example, it is impossible to make a combo using multiple face buttons. To create a combo, use the button + button syntax as normal:
Code: Select all
controller_key_sequence = "controller-lefttrigger + controller-righttrigger + controller-y"
The game's locale system provides a handful of macros to display control inputs. You can find a list of these macros on the wiki. Using these macros in locale will automatically choose the correct representation for the input method that you are using.
For example, this stone furnace description:
Code: Select all
[entity-description]
stone-furnace=__CONTROL__open-gui__ to open, __CONTROL_mine__ to remove.
Reading and reacting to changes in input method
The LuaPlayer::input_method read contains the player's current input method, as a variant of defines.input_method. The on_player_input_method_changed event will be called whenever a player changes their input method.
LuaPlayer::input_method will only be accurate during and after on_player_input_method_changed; reading LuaPlayer::input_method during on_player_created or on_player_joined_game is unreliable. When a player is created, their input method will always initially be keyboard_and_mouse, and if they are using a controller, on_player_input_method_changed will be called later. Always assume that a new player is using a keyboard and mouse, and only activate controller-specific behavior during on_player_input_method_changed.
Quick panel - shortcut bar
When using a controller, the standard hotbar and shortcut bar are replaced by the quick panel. The "tools" tab of the quick panel contains the shortcut bar buttons:
The shortcuts in this quick panel are not able to be rearranged by the user. The quick panel logic will arrange the shortcuts based on their prototype order. It is very strongly recommended that mods order their shortcuts to be after all of the vanilla shortcuts, as to not hurt muscle memory for vanilla tools.
Vanilla shortcut order strings
- toggle-alt-mode: a[alt-mode]
- undo: b[blueprints]-a[undo]
- copy: b[blueprints]-b[copy]
- cut: b[blueprints]-c[cut]
- paste: b[blueprints]-c[paste]
- import-string: b[blueprints]-d[import]
- give-blueprint: b[blueprints]-e[blueprint]
- give-blueprint-book: b[blueprints]-f[book]
- give-deconstruction-planner: b[blueprints]-g[deconstruction-planner]
- give-upgrade-planner: b[blueprints]-h[upgrade-planner]
- toggle-personal-roboport: c[toggles]-a[roboport]
- toggle-equipment-movement-bonus: c[toggles]-b[exoskeleton]
Mod GUIs
The game includes a heuristic to select GUI elements in the currently opened GUI. For modded GUIs, this heuristic will only apply to a window if it is currently contained in LuaPlayer::opened. If a mod GUI is not set to opened, the player has to use free-cursor mode to interact with it. It is recommended that this be avoided whenever is reasonable.
Click modifiers and mouse buttons
For the purposes of GUI events, the following mappings are made:
- controller-a: Left-click
- controller-x: Right-click
- controller-lefttrigger: CONTROL modifier
- controller-righttrigger: SHIFT modifier
As a potential workaround for the reduced capabilities, 1.1.83 has also added cursor_display_location to on_gui_click and custom input events. This property gives the current location of the mouse cursor on the user's screen. This can be used to create a context menu where the various actions can be contained. Keep in mind that for the controller heuristic to focus the context menu, it needs to be set as LuaPlayer::opened.
Game controller interaction modes
The game's heuristic uses the element type and a combination of other factors to determine if it should be selected by a controller. However, the heuristic may not perform as expected on modded GUIs, especially if a lot of GUI tricks or hacks are in use. Writing LuaGuiElement::game_controller_interaction will modify the heuristic's behavior for the given element.
Convenience bindings
It is notably more cumbersome to navigate a GUI with a controller than with a mouse. Because of this, it is recommended to add optional custom-inputs to speed up GUI interaction. For example, if a GUI has multiple tabs, adding optional bindings to switch tabs without having to navigate to and click them would be beneficial. Take care to only listen for these bindings if the GUI is actively opened, to avoid conflicts with other mods.