---
title: KeyController and focused_on
description: "Learn how to fix focus problems with keyboard and controller, and how to add extra functionality to your UI in Ren'Py."
url: "https://feniksdev.com/tool/keycontroller-and-focused_on/"
updated: "2025-02-09"
category: Controller Support Expansion
---

# KeyController and focused_on

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:

[https://itch.io/embed/2766391?bg_color=21212d&fg_color=f7f7ed&link_color=f93c3e&border_color=ff8335](https://itch.io/embed/2766391?bg_color=21212d&fg_color=f7f7ed&link_color=f93c3e&border_color=ff8335)

   **Contents**  [hide](#)     [Examples](#Examples)  [Example 1](#Example_1)  [Example 2](#Example_2)  [Example 3](#Example_3)  [Properties](#Properties)  [key](#key)  [action](#action)  [activate_sound](#activate_sound)  [capture](#capture)

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:

```renpy
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](https://www.renpy.org/doc/html/keymap.html). 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:

[![An image of a gray bedroom with a bed on the left and a desk on the right.](https://img.itch.zone/aW1hZ2UvNjYzOTgxLzM1Nzc0NzIucG5n/original/GXlSFg.png)](https://sigelus.itch.io/visual-novel-backgrounds-apartment-bedroom)
Image from sigelus on itch.io

[You can find the image from sigelus on itch.io here.](https://sigelus.itch.io/visual-novel-backgrounds-apartment-bedroom)

Let's say that the horse picture above the desk and the bed on the left are buttons that can be interacted with.

```renpy
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:

```renpy
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:

```renpy
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

```renpy
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](https://www.renpy.org/doc/html/keymap.html) 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`
