Controller Support Expansion for Ren’Py includes several features to improve controller and keyboard support in Ren’Py. Pick up the tool from itch.io if you haven’t already:
The KeyController is a special class which helps declare relationships between buttons. It can be provided instructions like “if the player is focused on the button with ID "desk"
and presses right
, focus on the button with the ID "bed"
. It helps to fix focus problems, like Ren’Py focusing the wrong button when you’re navigating the UI, or skipping over buttons in hbox or vbox. If you’re wondering how to fix focus issues or add extra functionality to your buttons, the KeyController is a great solution.
Examples
The format to set up a KeyController is:
focused_on "DISPLAYABLE_ID" key "SOME_EVENT" action SomeAction()
In this case, "DISPLAYABLE_ID"
should be the ID of a displayable in the screen. You assign IDs to displayables with the id
property e.g. textbutton "Hello" id "my_hello_id"
. In order for the rest of the code to run, the displayable with the provided ID must be the currently focused one.
Next, "SOME_EVENT"
will be an event or list of events as seen in Customizing the Keymap. Some examples are event names like "focus_left"
(which covers any keyboard or controller presses which focus something to the left) or direct key presses like "K_DELETE"
. It can also be a list of either of these e.g. [ "toggle_skip", "pad_leftshoulder_press" ]
.
Finally, SomeAction()
is any screen action you want to execute when the provided conditions are met (aka that Ren’Py is both currently focused on the displayable with the provided ID, and the provided event occurred).
Example 1
Let’s look at a full example, with the screen and everything. Say you have an image like the following:
You can find the image from sigelus on itch.io here.
Let’s say that the horse picture above the desk and the bed on the left are buttons that can be interacted with.
screen bedroom():
add "backgrounds/bedroom_day.jpg"
imagebutton:
id "horse"
auto "bedroom/horse_image_%s.png"
action Jump("view_horse_picture")
imagebutton:
id "bed"
auto "bedroom/bed_%s.png"
action Jump("go_to_bed")
![An image of a bedroom. The bed on the left and horse image on the right are highlighted in red.](https://feniksdev.com/wp-content/uploads/2025/02/bedroom_buttons-1024x576.png)
Let’s say that Ren’Py does not seem to want to focus the bed when you hit left
while focused on the horse image. You can use focused_on
to define that relationship:
screen bedroom():
add "backgrounds/bedroom_day.jpg"
imagebutton:
id "horse"
auto "bedroom/horse_image_%s.png"
action Jump("view_horse_picture")
imagebutton:
id "bed"
auto "bedroom/bed_%s.png"
action Jump("go_to_bed")
focused_on "horse" key "focus_left" action SetFocus("bedroom", "bed")
Example 2
You can also use the KeyController to do other special actions when particular buttons are pressed; say, for example, you have it set up so that pressing the “i” key on the keyboard or Y key on a controller while focused on a button will investigate it:
screen bedroom():
add "backgrounds/bedroom_day.jpg"
imagebutton:
id "horse"
auto "bedroom/horse_image_%s.png"
action Jump("view_horse_picture")
imagebutton:
id "bed"
auto "bedroom/bed_%s.png"
action Jump("go_to_bed")
focused_on "horse" key "focus_left" action SetFocus("bedroom", "bed")
focused_on "horse" key ["K_i", "pad_y_press"] action Jump("investigate_horse")
focused_on "bed" key ["K_i", "pad_y_press"] action Jump("investigate_bed")
You can add multiple focused_on
key + action combos for the same ID, as seen above where there are two for the “horse” ID. This works because the events they are listening for are different.
Example 3
screen preferences():
## ... full screen omitted
focused_on "pick_icons" key "focus_left" action CycleControllerLayout(reverse=True)
focused_on "pick_icons" key "focus_right" action CycleControllerLayout(reverse=False)
This means that when the button with the ID "pick_icons"
is focused, and the left
arrow key or controller D-pad/stick is moved, it will run the action CycleControllerLayout(reverse=True)
which cycles through the different controller layouts in reverse. The same happens for hitting right
while focused on the "pick_icons"
button, but it cycles normally (not in reverse order).
Properties
The full list of properties used by the KeyController are listed below.
key
This should be a string or a list of such strings corresponding to event names. See Customizing the Keymap in the docs for valid event names.
Note that this class does not convert custom gamepad events to their remapped format, so you may need to use the pad_config.get_event
function to convert it e.g. key pad_config.get_event("investigate")
.
action
The action or a list of actions to execute if the provided event occurs while focused on a displayable with the given ID. e.g. action Notify("You pressed the button")
activate_sound
Optional. A sound to play when the action is triggered. e.g. activate_sound "oof.ogg"
capture
Optional. If True, the default, the KeyController will ignore the event afterwards, preventing it from being passed along to the rest of the UI. If False, the event will be passed along to the rest of the UI after executing the action. e.g. capture False