.. _keymap:

Customizing the Keymap
======================

The variable :var:`config.keymap` contains a map from event names to lists
of keysyms that cause those events to occur.

.. note::

    Many players have learned the default set of Ren'Py keybindings, and
    expect them to be the same from game to game.

In Ren'Py keysyms are strings representing mouse buttons, joystick buttons,
or keyboard keys.

Mouse buttons use keysyms of the form 'mouseup_#' or 'mousedown_#',
where # is a button number. Ren'Py assumes a five button mouse,
where buttons 1, 2, and 3 are the left, middle, and right buttons, while
buttons 4 and 5 are generated by scrolling the wheel up and down.
For example, "mousedown_1" is generally a press of the left mouse button,
"mouseup_1" is a release of that button, and "mousedown_4" is a turn of the
scroll wheel to the top.

There are two kinds of keyboard keysyms. The first is a string containing a
character that is generated when a key is pressed. This is useful for
binding alphabetic keys and numbers. Examples of these keysyms include "a", "A", and "7".
Note that these are case sensitive, "a" does not match "A". This kind of keysym
is only useful when an event generates text - for example, the a key being
released will not match ``keyup_a``, as no text is generated.

Keyboard keysyms can also be the symbolic name for the key. This can be any of
the K\_ constants taken from pygame.constants. This type of keysym looks like
"K\_BACKSPACE", "K\_RETURN", and "K\_TAB"; a full list of this kind of keysyms may
be found `here <http://www.pygame.org/docs/ref/key.html>`_.

Keyboard and Mouse keysyms may be preceded by the following prefixes,
separated by underscores:

alt
    Matches if the Alt key is pressed. Keysyms without this prefix match
    when the Alt key is not pressed.
meta
    Matches if the Meta, Command, or Windows key is pressed. Keysyms without
    this prefix match when the meta key is not pressed.
ctrl
    Matches if the Ctrl key is pressed. Keysyms without this prefix match
    when the Ctrl key is not pressed. (Ctrl is not very useful, as it
    usually triggers skipping.)
osctrl
    This is Alt on the Macintosh, and Ctrl elsewhere.
anymod
    Matches regardless of the state of the Alt, Meta, or Ctrl keys.
shift
    Matches when the Shift key is pressed.
noshift
    Matches when the Shift key is not pressed.
caps
    Matches when the Caps Lock key is on.
nocaps
    Matches when the Caps Lock key is off.
num
    Matches when the Num Lock key is on.
nonum
    Matches when the Num Lock key is off.
repeat
    Matches when the key is a repeat due to the key being held down. Keysyms
    without the repeat or any prefixes do not match repeats. (This does not
    work with mouse buttons.)
anyrepeat
    Matches both initial keypresses and repeats.
keydown
    Matches when the key is being pressed down (the default).
keyup
    Matches when the key is being released.

For example, the keysym "shift_alt_K_F5" will match the F5 key being pressed
while Shift and Alt are held down. The keysym "shift_mouse_1" will match
the left mouse button being pressed while Shift is held down.

To change a binding, update the appropriate list in :var:`config.keymap`. The
following adds the 't' key to the list of keys that dismiss a say
statement, and removes the space key from that list. ::

    init python:
        config.keymap['dismiss'].append('K_t')
        config.keymap['dismiss'].remove('K_SPACE')

The default keymap is contained inside renpy/common/00keymap.rpy, and
as of version 8.4.0 is as follows::

    config.keymap = dict(

        # Bindings present almost everywhere, unless explicitly
        # disabled.
        rollback = [ 'anyrepeat_K_PAGEUP', 'anyrepeat_KP_PAGEUP', 'K_AC_BACK', 'mousedown_4' ],
        screenshot = [ 'alt_K_s', 'alt_shift_K_s', 'noshift_K_s' ],
        toggle_afm = [ ],
        toggle_fullscreen = [ 'alt_K_RETURN', 'alt_K_KP_ENTER', 'K_F11', 'noshift_K_f' ],
        game_menu = [ 'K_ESCAPE', 'K_MENU', 'K_PAUSE', 'mouseup_3' ],
        hide_windows = [ 'mouseup_2', 'noshift_K_h' ],
        launch_editor = [ 'shift_K_e' ],
        dump_styles = [ ],
        reload_game = [ 'alt_K_r', 'shift_K_r' ],
        inspector = [ 'alt_noshift_K_i', 'shift_K_i' ],
        full_inspector = [ 'alt_shift_K_i' ],
        developer = [ 'alt_K_d', 'shift_K_d', ],
        quit = [ ],
        iconify = [ ],
        help = [ 'K_F1', 'meta_shift_/' ],
        choose_renderer = ['alt_K_g', 'shift_K_g' ],
        progress_screen = [ 'alt_shift_K_p', 'meta_shift_K_p', 'K_F2' ],
        bubble_editor = [ 'alt_K_b', 'shift_K_b' ],

        # Accessibility.
        accessibility = [ 'shift_K_a' ],
        self_voicing = [ 'alt_K_v', 'K_v' ],
        clipboard_voicing = [ 'alt_shift_K_c', 'shift_K_c' ],
        debug_voicing = [ 'alt_shift_K_v', 'meta_shift_K_v' ],
        extra_voicing = [ '?' ],

        # Say.
        rollforward = [ 'anyrepeat_K_PAGEDOWN', 'anyrepeat_KP_PAGEDOWN', 'mousedown_5', ],
        dismiss = [ 'K_RETURN', 'K_SPACE', 'K_KP_ENTER', 'K_SELECT', 'mouseup_1' ],
        dismiss_unfocused = [ ],

        # Pause.
        dismiss_hard_pause = [ ],

        # Focus.
        focus_left = [ 'anyrepeat_K_LEFT', 'anyrepeat_KP_LEFT' ],
        focus_right = [ 'anyrepeat_K_RIGHT', 'anyrepeat_KP_RIGHT' ],
        focus_up = [ 'anyrepeat_K_UP', 'anyrepeat_KP_UP' ],
        focus_down = [ 'anyrepeat_K_DOWN', 'anyrepeat_KP_DOWN' ],

        # Button.
        button_ignore = [ 'mousedown_1' ],
        button_select = [ 'K_RETURN', 'K_KP_ENTER', 'K_SELECT', 'mouseup_1',  ],
        button_alternate = [ 'mouseup_3' ],
        button_alternate_ignore = [ 'mousedown_3' ],

        # Input.
        input_backspace = [ 'anyrepeat_K_BACKSPACE' ],
        input_enter = [ 'K_RETURN', 'K_KP_ENTER' ],
        input_next_line = [ 'shift_K_RETURN', 'shift_K_KP_ENTER' ],
        input_left = [ 'anyrepeat_K_LEFT', 'anyrepeat_KP_LEFT' ],
        input_right = [ 'anyrepeat_K_RIGHT', 'anyrepeat_KP_RIGHT' ],
        input_up = [ 'anyrepeat_K_UP', 'anyrepeat_KP_UP' ],
        input_down = [ 'anyrepeat_K_DOWN', 'anyrepeat_KP_DOWN' ],
        input_delete = [ 'anyrepeat_K_DELETE', 'anyrepeat_KP_DELETE' ],
        input_home = [ 'K_HOME', 'KP_HOME', 'meta_K_LEFT' ],
        input_end = [ 'K_END', 'KP_END', 'meta_K_RIGHT' ],
        input_copy = [ 'ctrl_noshift_K_INSERT', 'ctrl_noshift_K_c', 'meta_noshift_K_c' ],
        input_paste = [ 'shift_K_INSERT', 'ctrl_noshift_K_v', 'meta_noshift_K_v' ],
        input_jump_word_left = [ 'osctrl_K_LEFT', 'osctrl_KP_LEFT' ],
        input_jump_word_right = [ 'osctrl_K_RIGHT', 'osctrl_KP_RIGHT' ],
        input_delete_word = [ 'osctrl_K_BACKSPACE' ],
        input_delete_full = [ 'meta_K_BACKSPACE' ],

        # Viewport.
        viewport_leftarrow = [ 'anyrepeat_K_LEFT', 'anyrepeat_KP_LEFT' ],
        viewport_rightarrow = [ 'anyrepeat_K_RIGHT', 'anyrepeat_KP_RIGHT' ],
        viewport_uparrow = [ 'anyrepeat_K_UP', 'anyrepeat_KP_UP' ],
        viewport_downarrow = [ 'anyrepeat_K_DOWN', 'anyrepeat_KP_DOWN' ],
        viewport_wheelup = [ 'mousedown_4' ],
        viewport_wheeldown = [ 'mousedown_5' ],
        viewport_drag_start = [ 'mousedown_1' ],
        viewport_drag_end = [ 'mouseup_1' ],
        viewport_pageup = [ 'anyrepeat_K_PAGEUP', 'anyrepeat_KP_PAGEUP'],
        viewport_pagedown = [ 'anyrepeat_K_PAGEDOWN', 'anyrepeat_KP_PAGEDOWN' ],

        # These keys control skipping.
        skip = [ 'anymod_K_LCTRL', 'anymod_K_RCTRL' ],
        stop_skipping = [ ],
        toggle_skip = [ 'K_TAB' ],
        fast_skip = [ '>', 'shift_K_PERIOD' ],

        # Bar.
        bar_activate = [ 'mousedown_1', 'K_RETURN', 'K_KP_ENTER', 'K_SELECT' ],
        bar_deactivate = [ 'mouseup_1', 'K_RETURN', 'K_KP_ENTER', 'K_SELECT' ],
        bar_left = [ 'anyrepeat_K_LEFT', 'anyrepeat_KP_LEFT' ],
        bar_right = [ 'anyrepeat_K_RIGHT', 'anyrepeat_KP_RIGHT' ],
        bar_up = [ 'anyrepeat_K_UP', 'anyrepeat_KP_UP' ],
        bar_down = [ 'anyrepeat_K_DOWN', 'anyrepeat_KP_DOWN' ],

        # Delete a save.
        save_delete = [ 'K_DELETE', 'KP_DELETE' ],

        # Save/load screen pagination.
        save_page_prev = ['mousedown_4'],
        save_page_next = ['mousedown_5'],

        # Draggable.
        drag_activate = [ 'mousedown_1' ],
        drag_deactivate = [ 'mouseup_1' ],

        # Debug console.
        console = [ 'shift_K_o', 'alt_shift_K_o' ],
        console_exit = [ 'K_ESCAPE', 'K_MENU', 'K_PAUSE', 'mouseup_3' ],
        console_older = [ 'anyrepeat_K_UP', 'anyrepeat_KP_UP' ],
        console_newer = [ 'anyrepeat_K_DOWN', 'anyrepeat_KP_DOWN' ],

        # Director
        director = [ 'noshift_K_d' ],

        # Ignored (kept for backwards compatibility).
        toggle_music = [ ],
        viewport_up = [ ],
        viewport_down = [ ],

        # Profile commands.
        performance = [ 'K_F3' ],
        image_load_log = [ 'K_F4' ],
        profile_once = [ 'K_F8' ],
        memory_profile = [ 'K_F7' ],
    )

Gamepad bindings work a little differently. Gamepad bindings work by mapping
a gamepad event to one or more Ren'Py event names. The default set of
gamepad bindings is given below::

    config.pad_bindings = {
        "pad_leftshoulder_press" : [ "rollback", ],
        "pad_lefttrigger_pos" : [ "rollback", ],
        "pad_back_press" : [ "rollback", ],

        "repeat_pad_leftshoulder_press" : [ "rollback", ],
        "repeat_pad_lefttrigger_pos" : [ "rollback", ],
        "repeat_pad_back_press" : [ "rollback", ],

        "pad_guide_press" : [ "game_menu", ],
        "pad_start_press" : [ "game_menu", ],

        "pad_y_press" : [ "hide_windows", ],
        "pad_x_press" : [ "button_alternate" ],

        "pad_rightshoulder_press" : [ "rollforward", ],
        "repeat_pad_rightshoulder_press" : [ "rollforward", ],

        "pad_righttrigger_pos" : [ "dismiss", "button_select", "bar_activate", "bar_deactivate" ],
        "pad_a_press" : [ "dismiss", "button_select", "bar_activate", "bar_deactivate"],
        "pad_b_press" : [ "game_menu" ],

        "pad_dpleft_press" : [ "focus_left", "bar_left", "viewport_leftarrow" ],
        "pad_leftx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ],
        "pad_rightx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ],

        "pad_dpright_press" : [ "focus_right", "bar_right", "viewport_rightarrow" ],
        "pad_leftx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ],
        "pad_rightx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ],

        "pad_dpup_press" : [ "focus_up", "bar_up", "viewport_uparrow" ],
        "pad_lefty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ],
        "pad_righty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ],

        "pad_dpdown_press" : [ "focus_down", "bar_down", "viewport_downarrow" ],
        "pad_lefty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ],
        "pad_righty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ],

        "repeat_pad_dpleft_press" : [ "focus_left", "bar_left", "viewport_leftarrow" ],
        "repeat_pad_leftx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ],
        "repeat_pad_rightx_neg" : [ "focus_left", "bar_left", "viewport_leftarrow" ],

        "repeat_pad_dpright_press" : [ "focus_right", "bar_right", "viewport_rightarrow" ],
        "repeat_pad_leftx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ],
        "repeat_pad_rightx_pos" : [ "focus_right", "bar_right", "viewport_rightarrow" ],

        "repeat_pad_dpup_press" : [ "focus_up", "bar_up", "viewport_uparrow" ],
        "repeat_pad_lefty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ],
        "repeat_pad_righty_neg" : [ "focus_up", "bar_up", "viewport_uparrow" ],

        "repeat_pad_dpdown_press" : [ "focus_down", "bar_down", "viewport_downarrow" ],
        "repeat_pad_lefty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ],
        "repeat_pad_righty_pos" : [ "focus_down", "bar_down", "viewport_downarrow" ],
    }

Gamepad buttons have an event name of the form "pad_*button*_press" or
"pad_*button*_release". Analog axis events have the form "pad_*axis*_pos",
"pad_*axis*_neg", or "pad_*axis*_zero". If held down, a second gamepad binding
is generated, with the "repeat\_" prefix.

Gamepads that do not work without special initialization are disabled by
default. This includes the Nintendo Switch Pro Controller, which requires
special initialization to work on a PC. This blocklisting is controlled by
:var:`config.controller_blocklist`.

.. include:: inc/keymap
