Skip to content
Feniks Development
  • Start Here
  • Glossary
  • Tools
  • Resources
  • What’s New
  • About
  • Contact
Toggle the button to expand or collapse the Menu

Virtual Keyboard

  1. Home>
  2. Feniks Tools>
  3. Virtual Keyboard

Easy Blinking

  • EasyBlink Class
  • EasyBlink Examples

Controller Support Expansion

  • What is the Controller Support Expansion?
  • How do I…? + Common Issues
  • Controller Viewport
  • Controller Bar
  • Virtual Cursor
  • Virtual Keyboard
  • StickEvent
  • KeyController and focused_on
  • FocusDisplayable
  • Remapping Controls
  • Controller and Keyboard Icons
  • Configuration Variables
  • Screen Actions and Values
  • Helper Functions and Classes
  • Engine Override Notes

Sound Disabler and Captions Tool

  • Disabling Sounds and Sound Categorization
View Categories
  • Home
  • Feniks Tools
  • Controller Support Expansion
  • Virtual Keyboard

Virtual Keyboard

9 min read

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:

Contents hide
Examples
Example 1
Example 2
Example 3
Example 4
Controller Input
InputLetter(id, letter, layer=None)
ShowOnscreenInput(screen=None, transition=None, *args, **kwargs)
UniversalInputToggle(id, **kwargs)
input_check(s, to_capitalize=False, properties=None, pad=10)
universal_input(prompt, default=”, allow=None, exclude='{}’,length=None, with_none=None, pixel_width=None, screen=None,mask=None, copypaste=True, multiline=False, **kwargs)
Virtual Keyboard Screens
Styling the Virtual Keyboard
A screen with a virtual QWERTY keyboard. It has a number row and a blank space above the keyboard that reads "Enter some text:"

The Controller Support Expansion for Ren’Py also includes a virtual keyboard which can be used to enter input such as character names without requiring a physical keyboard. It has several shortcuts for controllers to make it easy to use.

Examples

The following are some examples of how to use the virtual keyboard to get input from the player.

Example 1

The first example is a very basic way to get input from the player.

default name = "Feniks"
label start():
    $ name = universal_input(_("Enter your name:"))
    "Your name is [name], is that right?"

This will show an input prompt to the player. If the player is using the mouse and keyboard, they will not be shown a virtual keyboard. If they are using a controller, the input will be shown using the onscreen_keyboard screen.

Example 2

The second example shows how you can pass arguments to the various input functions:

default name = "Feniks"
label start():
    $ name = universal_input(_("Enter your name:"), length=20, pixel_width=300,
        allow="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ '-")
    "Your name is [name], is that right?"

This example is similar to the previous one, but has some constraints on valid input: in particular, it has to be a letter, space, apostrophe, or hyphen, it can be a maximum of 20 characters long, and the total width of the letters can’t be more than 300 pixels wide. These arguments are identical to the ones seen in renpy.input!

Example 3

Here is an example that uses the virtual numpad rather than the keyboard:

default pin = ""
label start():
    $ pin = universal_input(_("Enter a 4-digit number:"),
        ## This could be specified, but it will automatically use the numpad
        ## since it only allows numbers
        # screen="onscreen_numpad", 
        allow='1234567890', length=4)
    "Your PIN is [pin]."

You may also use $ pin = int(pin) to turn the result into a number rather than a string, if you need to compare it to other numbers.

Example 4

This example has a screen with multiple inputs. The player can select an input, which will show the virtual keyboard if they are using a controller, or simply enable the input if not.

A screen with a column of buttons. The first says "First Name: Feniks" and is highlighted in orange. The second says "Last Name: Dev". The third says "Number: " and the final says "Done".
A virtual keyboard is on-screen with the prompt "Enter your first name:". It is filled out with the name "Feniks".
default demo_first_name = "Feniks"
default demo_last_name = "Dev"
default demo_number = ""
screen naming_screen():
    ## The "object" here is `store` since it's a regular store variable.
    ## If the variable was persistent.name, it would use `persistent` instead.
    default first_name_input = EnterInputValue(store, 'demo_first_name')
    default last_name_input = EnterInputValue(store, 'demo_last_name')
    default number_input = EnterInputValue(store, 'demo_number')

    add "#601249bb"

    style_prefix 'demo_name'

    vbox:
        button:
            default_focus True
            ## Ensure you can type without needing to hover this button
            key_events True
            ## This action "does the right thing" based on whether the player
            ## is using a controller or not. For it to work, you need to give
            ## the input a unique ID and pass that into the action. You can also
            ## pass other properties, like the prompt or whether to dim the
            ## screen. Passing the ID ensures it gets the same properties
            ## as the original input, like length and allowed characters.
            action UniversalInputToggle('first_name',
                prompt=_("Enter your first name:"), dim=True)
            has hbox
            text _("First Name:")
            # The actual input, which uses the EnterInputValue earlier
            input value first_name_input id 'first_name' length 15:
                allow "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -'"
                pixel_width 400

        button:
            key_events True
            action UniversalInputToggle('last_name',
                prompt=_("Enter your last name:"), dim=True)
            has hbox
            text _("Last Name:")
            # The actual input, which uses the EnterInputValue earlier
            input value last_name_input id 'last_name' length 15:
                allow "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -'"
                pixel_width 400

        button:
            key_events True
            action UniversalInputToggle('number',
                prompt=_("Enter a number:"), dim=True)
            has hbox
            text _("Number:")
            # The actual input, which uses the EnterInputValue earlier
            input value number_input id 'number' length 4 allow '1234567890'

        textbutton _("Done") action Return() xalign 0.5

This example uses the class EnterInputValue. This is included with the controller support expansion pack, or you can also find it here: https://github.com/shawna-p/RenPyControllerGUI/blob/main/game/optional%20files/mobile_input.rpy. It is a special kind of InputValue which disables the input when the Enter key is pressed, but any other InputValue can be used here as well (link to InputValue in the Ren’Py docs).

The important part is that each of your input elements needs an ID, and that ID needs to be passed to the UniversalInputToggle action. Doing so ensures that the virtual keyboard input will have all the same properties as the one on your screen, such as allow, length, and more. You can pass in individual properties to overwrite them – the example passes in prompt so that the prompt appears for the virtual keyboard indicating what the input is for. It also uses dim=True so that the screen behind the virtual keyboard is dimmed.

Note: Much of the rest of this page is for reference purposes and internal use – these are the functions and actions used to make the virtual keyboard work. If you just want to use the virtual keyboard in your game, use the Examples section to see how to use these features, and refer back to the individual functions and actions used in the examples if you’d like to know more.

Controller Input

Inside screens, the screen language keyword controller_input can be used to show the virtual keyboard when a controller is used. ControllerInput inherits from the built-in Input class and shares all the same properties as it: see https://www.renpy.org/doc/html/screens.html#input for more. There are a few functions and actions specific to controller input:

InputLetter(id, letter, layer=None)

InputLetter is a screen action which can be used to add a letter to a ControllerInput. It takes three arguments:

id

This is the ID of the ControllerInput. e.g. id="tinput"

letter

This is a string of the text to add to the ControllerInput. e.g. letter="a"

layer

The layer the screen with the ControllerInput is on. This can usually just be None to automatically determine it.

e.g. action InputLetter("my_input", "f")

This action is used in the virtual keyboard screens to add content to the input with the controller.

ShowOnscreenInput(screen=None, transition=None, *args, **kwargs)

A screen action which will show an onscreen keyboard for controller input. It takes the following arguments:

screen

If this is not provided or None, one of “onscreen_keyboard” or “onscreen_numpad” will be used, depending on which characters are allowed in the input. The numpad will only be used if the input only accepts numbers. e.g. screen="onscreen_keyboard"

transition

If provided, this transition will be used to show the onscreen keyboard. e.g. transition=Dissolve(1.0)

args, kwargs

Any other arguments or keyword arguments will be passed along to the input screen being used for the virtual keyboard. In particular, allow and exclude keyword arguments may be provided, along with other input keyword arguments, to customize the virtual keyboard.

e.g. ShowOnscreenInput("onscreen_keyboard", dissolve, allow="0123456789")

UniversalInputToggle(id, **kwargs)

UniversalInputToggle is a screen action which can be used to toggle the provided InputValue if the player is using mouse and keyboard, or if the player is using a controller, it will show the virtual keyboard to enter input via ShowOnscreenInput.

id

This should be the ID of an input displayable declared on the screen. This will be used to get the correct InputValue and other input properties to re-use on the virtual keyboard screen. e.g. id="my_input"

kwargs

Any other keyword arguments will be passed along to ShowOnscreenInput if the virtual keyboard is used. The most notable are dim, which you may want to set to dim=True to dim the screen behind the virtual keyboard, and prompt, which will be displayed above the input text.

e.g. UniversalInputToggle("first_name_input", dim=True, prompt=_("What's your first name?"))

input_check(s, to_capitalize=False, properties=None, pad=10)

This helper function changes the text in the virtual keyboard to suit the provided input properties and capitalize it if the shift button is active. It takes the following arguments:

s

A string of letters to use for a given keyboard row e.g. "qwertyuiop". See https://feniksdev.com/tool/configuration-variables/#Input for the different keyboard rows.

to_capitalize

Whether the letters in the provided string should be returned with their capitalized version or not. See https://feniksdev.com/tool/configuration-variables/#Input for the SHIFT_DICT which is used for symbols and other characters.

properties

This should be a dictionary with properties from the input field, usually automatically provided. If this includes the keys allow or exclude, those will be used to determine which letters to remove from the string (so they don’t appear as buttons on the virtual keyboard).

pad

By default, virtual keyboard rows are 10 characters long. In order to keep all the virtual keyboard keys focusable even if they do not have valid letters in them for this input, pad=10 fills invalid letter keys with blank input and ensures the row remains at least 10 characters long. This prevents the keyboard from changing sizes when some letters aren’t usable.

universal_input(prompt, default=”, allow=None, exclude='{}’,
length=None, with_none=None, pixel_width=None, screen=None,
mask=None, copypaste=True, multiline=False, **kwargs)

This function borrows from https://www.renpy.org/doc/html/input.html#renpy.input and will choose to use either renpy.input or controller_input based on whether the last input type was a controller or not. It can be used in the same situations as renpy.input and accepts all the same arguments e.g.

default name = "Feniks"
label start:
    $ name = universal_input(_("What is your name?"), length=20)

Virtual Keyboard Screens

Controller Support Expansion for Ren’Py comes with two screens which are used to show the virtual keyboard to the player: onscreen_keyboard and onscreen_numpad. The former is the most commonly used screen; onscreen_numpad is only used for input which only accepts numbers as input.

A screenshot of a game with a virtual numpad on the screen. It has numbers from 0-9, arrows to adjust the position of the caret, backspace, and done buttons. Text above the numpad reads "Enter a number:"

Styling the Virtual Keyboard

Inside the controller_input.rpy file you will find declarations for the two onscreen keyboard screens, as well as a few general styling constants declared at the top (as seen in https://feniksdev.com/tool/configuration-variables/#Input). While advanced users are free to adjust the screens directly, most users should adjust the ckeyboard_ styles below the screen to update the styling.

Updated on February 9, 2025
Virtual CursorStickEvent

Leave a Reply Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© Copyright – Feniks with OceanWP
Close Menu