Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pojavlauncherteam/pojavlauncher/llms.txt

Use this file to discover all available pages before exploring further.

PojavLauncher ships with a fully visual touch-control editor that lets you design exactly the on-screen layout you need — from a minimal set of movement and inventory keys to a comprehensive layout with joysticks, drawers, and custom macros. Control layouts are stored as plain JSON files and can be shared across devices or downloaded from the community. Every profile can specify its own layout file, making it straightforward to use a different control scheme for 1.8 PvP versus a 1.20 survival build.
PojavLauncher has been discontinued. Its successor is Amethyst Android. These docs describe the final released state of PojavLauncher.

Default Control Layout

When no custom layout has been set and no default.json exists in the controlmap folder, the launcher generates a built-in default layout. It includes:
ButtonKey / Action
KeyboardOpens the virtual keyboard
GUIToggles the control overlay visibility (show/hide all buttons)
PRIPrimary (left) mouse click
SECSecondary (right) mouse click
MouseToggles the virtual mouse cursor mode
F3Debug screen
TOpen chat
TabShow player list
F5Toggle third-person camera
W / A / S / DMovement (toggle-mode, so you can hold a direction)
EInventory
ShiftSneak (toggle)
SpaceJump
The default layout file path is:
<game_home>/controlmap/default.json
Where <game_home> defaults to <external_storage>/games/PojavLauncher.

Opening the Control Editor

From the main screen, tap the Custom Controls button (the gamepad icon in the toolbar). The CustomControlsActivity opens and loads the current default layout. You can also reach the editor from inside a running game via the in-game overlay menu. The editor canvas fills the screen, showing every button in its actual position and size. A drawer button (chevron icon) in the corner opens the editor action menu.

Editor Action Menu

Swipe in or tap the drawer button to reveal the action menu:
OptionWhat it does
Add ButtonPlaces a new ControlData button at the centre of the screen
Add DrawerPlaces a new ControlDrawerData drawer that expands sub-buttons
Add JoystickPlaces a new ControlJoystickData joystick
LoadOpens a file picker rooted at <game_home>/controlmap/ to load an existing layout
SaveSaves the current layout to the same file it was loaded from
Set as DefaultMarks the current layout as the global default (PREF_DEFAULTCTRL_PATH)
ExportSaves the layout and shares it via Android’s share sheet as a .json file

Control Elements

Buttons (ControlData)

A ControlData object represents a single tappable button. Its JSON fields are:
FieldTypeDescription
namestringLabel displayed on the button face
keycodesint[4]Up to four GLFW keycodes (or special-button constants) sent when tapped; unused slots default to GLFW_KEY_UNKNOWN
dynamicXstringExpression defining the button’s X position (see Dynamic Positioning)
dynamicYstringExpression defining the button’s Y position
widthfloatButton width in dp
heightfloatButton height in dp
isTogglebooleanIf true, the button stays pressed until tapped again (useful for movement keys)
passThruEnabledbooleanIf true, touch events pass through to the game canvas below the button
opacityfloatVisibility from 0.0 (invisible) to 1.0 (fully opaque)
bgColorintARGB background colour
strokeColorintARGB border colour
strokeWidthfloatBorder thickness in dp
cornerRadiusfloatCorner rounding from 0 % to 100 %
isSwipeablebooleanIf true, swiping across the button fires successive key events
displayInGamebooleanShow this button while the game has grabbed the mouse (gameplay mode)
displayInMenubooleanShow this button while a GUI / menu is open
isHideableboolean (transient)Whether the toggle-controls button can hide this button

Special Button Constants

Several reserved keycode values trigger launcher-level actions rather than sending a keypress to the game:
ConstantValueAction
SPECIALBTN_KEYBOARD-1Opens the Android virtual keyboard
SPECIALBTN_TOGGLECTRL-2Toggles the visibility of all hideable control buttons
SPECIALBTN_MOUSEPRI-3Fires a primary (left) mouse click
SPECIALBTN_MOUSESEC-4Fires a secondary (right) mouse click
SPECIALBTN_VIRTUALMOUSE-5Toggles the virtual mouse cursor on or off
SPECIALBTN_MOUSEMID-6Fires a middle mouse click
SPECIALBTN_SCROLLUP-7Scrolls up
SPECIALBTN_SCROLLDOWN-8Scrolls down
SPECIALBTN_MENU-9Opens the in-launcher overlay menu
To assign a special action to a button, set its keycodes[0] to the corresponding negative integer value.

Drawers (ControlDrawerData)

A drawer is a collapsed button that expands a row of sub-buttons when tapped, keeping the main layout uncluttered. Its structure:
{
  "properties": { /* ControlData for the drawer handle */ },
  "buttonProperties": [ /* array of ControlData for sub-buttons */ ],
  "orientation": "LEFT"
}
The orientation field controls the direction the sub-buttons expand when the drawer is opened:
  • DOWN, LEFT, UP, RIGHT — expand in that cardinal direction
  • FREE — sub-buttons can be positioned freely

Joysticks (ControlJoystickData)

A ControlJoystickData extends ControlData with two extra fields:
FieldTypeDescription
forwardLockbooleanWhen true, releasing the joystick keeps the last forward direction held
absolutebooleanWhen true, the joystick thumb jumps to your initial touch point (absolute mode); when false, the thumb stays centred and only the delta matters (relative mode)

Dynamic Positioning

Button positions are not stored as fixed pixel coordinates. Instead, each button stores two expression strings (dynamicX, dynamicY) that are evaluated at runtime using the exp4j expression engine. This makes layouts automatically adapt to different screen sizes and orientations. Available variables:
VariableValue
top0 (top edge)
left0 (left edge)
rightscreen_width − button_width
bottomscreen_height − button_height
widthButton width in pixels
heightButton height in pixels
screen_widthPhysical screen width in pixels
screen_heightPhysical screen height in pixels
marginComputed margin distance (based on button size preference)
preferred_scaleGlobal button scale preference value
Two helper functions are also available:
  • dp(x) — converts x from pixels to dp
  • px(x) — converts x from dp to pixels
Example expressions from the default layout:
// Keyboard button — top-right area
dynamicX = "${margin} * 3 + ${width} * 2"
dynamicY = "${margin}"

// Jump button — bottom-right
dynamicX = "${right} - ${margin} * 2 - ${width}"
dynamicY = "${bottom} - ${margin} * 2 - ${height}"

Importing and Exporting Layouts

Control layouts are standard JSON files. To bring in a layout from another source:
1

Copy the JSON file to the controlmap folder

Place the .json file in <game_home>/controlmap/ using a file manager or USB transfer.
2

Load it in the editor

Open the control editor, tap the drawer button, and select Load. Navigate to the file and tap it to load the layout onto the canvas.
3

Set it as default or assign it to a profile

Tap Set as Default to make it the global layout, or close the editor and assign the file path to a specific profile via the profile editor’s Control layout field.
To export your layout for sharing:
1

Open the editor and load the layout you want to share

Use Load to open the target file if it is not already active.
2

Tap Export

The editor saves the file and opens Android’s share sheet. Send it via any available app.

Gamepad Support

If you have a Bluetooth or USB gamepad, PojavLauncher includes a Gamepad Mapper that lets you assign gamepad buttons and axes to in-game actions. Access the mapper by long-pressing the News button on the main screen. Gamepad configuration is stored separately from touch control layouts and applies on top of them.
Detailed gamepad configuration is covered in the Configuration section of these docs. Touch control layouts and gamepad mappings are independent — you can use both simultaneously.

Next Steps

Playing the Game

Understand in-game touch gestures and how to exit the game.

Profiles

Assign a specific control layout to a profile.

Build docs developers (and LLMs) love