Convert control-layout JSON between Zalith Launcher 2 and FoldCraftLauncher.
Note: This tool was originally created by iqisge-gif, who is no longer actively maintaining the converter. This repository continues its development.
# ZL -> FCL
python cc.py zl2fcl zl_layout.json fcl_layout.json
# FCL -> ZL
python cc.py fcl2zl fcl_layout.json zl_layout.json
# auto-detect format
python cc.py auto input.json output.jsonZero dependencies. Python 3.8+ standard library only.
git clone https://github.com/NingZeStudio/control-converter.git
cd control-converterNo pip install needed. Just run python cc.py.
Try it online: cc.miawa.cn -- web-based converter. API at api.cc.miawa.cn.
dist/libcc.so is a Go re-implementation of cc.py, built as an Android aarch64 JNI shared library. It is compiled in an Android (arm64) environment (e.g. Termux), then loaded from Java via System.loadLibrary("cc"). See BUILD.md for build instructions.
Zalith Launcher 2 and FoldCraftLauncher use completely different JSON schemas for their on-screen control layouts -- different key codes, color formats, size units, and event models. This tool translates between the two, handling:
- Key mapping -- bi-directional GLFW key names <-> FCL integer keycodes (100+ keys, 3 mouse buttons, scroll events)
- Color conversion -- ZL Compose Color (signed Long packed sRGB) <-> FCL ARGB int, with alpha blending
- Size conversion -- ZL dp/percentage/wrap_content <-> FCL ABSOLUTE/PERCENTAGE with per-mille scaling, including wrap_content dp estimation
- Style mapping -- bidirectional button style conversion (text, border, fill, corner radius, pressed state)
- Event translation -- key presses, launcher events (scroll, IME toggle, menu), send_text, layer visibility toggles
- Layer preservation -- ZL layers -> FCL view groups with group-level visibility and order
- Direction controls -- FCL rocker <-> ZL native joystick (ZL editor v12); FCL direction pad <-> ZL button grids
- Roundtrip metadata -- embeds
_control_convertermetadata in output so the original layout can be recovered
Modes that can't map 1:1 use documented fallbacks with substitution tracking, printed to stderr.
| Feature | CLI | API |
|---|---|---|
| ZL -> FCL | zl2fcl |
/convert |
| FCL -> ZL | fcl2zl |
/convert |
| Auto-detect | auto |
/convert |
| Direction controls | --include-directions |
includeDirections |
| Lossless mode | --lossless |
lossless |
| Absolute -> percentage | --absolute-as-percentage |
absoluteAsPercentage |
| Strip metadata | --strip-meta |
stripMeta |
| Usable safe mode | --usable |
usable |
| JSON comment support | -- | /convert-file |
| Health check | -- | GET /health |
python cc.py <mode> <input> <output> [options]| Mode | Direction |
|---|---|
zl2fcl |
Zalith Launcher 2 -> FoldCraftLauncher |
fcl2zl |
FoldCraftLauncher -> Zalith Launcher 2 |
auto |
Detect format and convert |
api |
Start HTTP API server |
| Flag | Effect |
|---|---|
--include-directions |
Convert FCL direction controls: ROCKER -> ZL joystick, direction pad -> ZL button grids |
--lossless |
Substitute unsupported controls instead of dropping them; also converts FCL directions |
--absolute-as-percentage |
Convert FCL absolute dp sizes to ZL percentage sizes |
--strict |
Fail on unsupported fields instead of warning |
--compact |
Output compact JSON (no whitespace) |
--strip-meta |
Remove _control_converter metadata from output |
--usable |
ZL->FCL structural safe mode; remove only large blank blockers |
--aspect 16/9 |
Screen aspect ratio for direction approximation (default: 1.778) |
Start the server:
python cc.py api --host 0.0.0.0 --port 8000POST /convert -- Convert layout in request body.
{
"mode": "zl2fcl",
"data": { ... },
"strict": false,
"stripMeta": false
}Response:
{ "ok": true, "data": { ... } }POST /convert-file -- Convert uploaded JSON file. Supports // and /* */ comments.
POST /convert-file?mode=zl2fcl&strict=false
Content-Type: application/json
{ ... layout with comments ... }
GET /health -- Health check.
{ "ok": true }- ZL
wrap_contentsizes have no FCL equivalent; estimated from text length and font size - ZL
hideWhenMouse/hideWhenGamepadlayer flags have no FCL equivalent; skipped with warning - FCL side mouse buttons 4-8 map to scroll events as fallback
- FCL
KEY_KPCOMMAhas no exact GLFW key; falls back to keypad decimal
All substitutions are tracked, documented with reasons, and printed to stderr.
MIT -- see LICENSE.