A customizable Android IME (Input Method Editor) built with Jetpack Compose and driven by JSON keyboard layout definitions.
| English QWERTY | Bopomofo (Dachen) | Number Pad |
|---|---|---|
![]() |
![]() |
![]() |
| Emoji | Key Preview | Pack Management |
|---|---|---|
![]() |
![]() |
![]() |
- JSON-driven layouts - Define keyboard layouts in JSON; import custom layouts from files
- Multiple keyboard packs - Swipe left/right to switch between enabled packs
- Sub-layout switching - Support for lowercase, uppercase, symbols, and custom sub-layouts within a pack
- Material You theming - Keyboard colors adapt to your wallpaper via Material 3 dynamic colors (Android 12+)
- Key preview popup - Visual feedback showing the pressed key label
- Haptic & sound feedback - Vibration and click sound on key press
- Pack management UI - Enable/disable, reorder, and delete keyboard packs from the settings screen
- Security-first import - Imported JSON is validated, sanitized, and re-serialized before storage
| Layout | Description |
|---|---|
| English QWERTY | Standard QWERTY with lowercase, uppercase, and symbols sub-layouts |
| Emoji | 1,184 emojis across 8 categories |
| Number Pad | Compact numeric keypad |
| Bopomofo (Dachen) | Taiwanese phonetic input layout |
Requires Android Studio with AGP 9.0+ and JDK 11+.
./gradlew assembleDebug
./gradlew installDebug- Install the app
- Open MeaninglessKeyboard from the launcher
- Tap Input Method Settings to enable the keyboard in system settings
- Select MeaninglessKeyboard as your active input method
Keyboard packs are defined as JSON files. Example structure:
{
"name": "My Layout",
"author": "Your Name",
"version": 1,
"defaultLayout": "main",
"layouts": {
"main": {
"rows": [
{
"keys": [
{ "label": "A", "output": "a", "width": 1 },
{ "label": "B", "output": "b", "width": 1 }
]
}
]
}
}
}- Text output:
{ "label": "A", "output": "a" }- commits text to the input field - Keycode:
{ "label": "Del", "keycode": "BACKSPACE" }- sends a key event (supported:BACKSPACE,ENTER,SHIFT,TAB,ARROW_LEFT,ARROW_RIGHT) - Layout switch:
{ "label": "123", "switchLayout": "symbols" }- switches to another sub-layout
Each key must have exactly one of output, keycode, or switchLayout.
| Field | Limit |
|---|---|
| File size | 512 KB |
| Pack/author name | 64 characters |
| Layouts per pack | 10 |
| Rows per layout | 50 |
| Keys per row | 20 |
| Key label | 8 characters |
| Key output | 32 characters |
| Key width | 0.5 - 10.0 |
./gradlew testUnit tests cover KeyAction parsing, KeyboardPackSanitizer validation boundaries, and built-in keyboard JSON assets.
This project is licensed under the GNU General Public License v3.0 or later.





