feat: data-driven virtual keyboard layouts

This commit is contained in:
Martin Prokoph
2025-05-19 16:20:46 +02:00
parent ecb7cfd888
commit 0dfd1994dc
13 changed files with 122 additions and 59 deletions

View File

@@ -148,6 +148,7 @@ public class MidnightControlsConfig extends MidnightConfig {
@Comment(category = SCREENS, centered = true, name="\uD83D\uDD27 UI Modifications") public static Comment _uiMods;
@Entry(category = SCREENS, name = "midnightcontrols.menu.move_chat") public static boolean moveChat = false;
@Entry(category = SCREENS, name = "Enable Shortcut in Controls Options") public static boolean shortcutInControls = true;
@Entry(category = MISC, name = "midnightcontrols.menu.virtual_keyboard_layout") public static String keyboardLayout = "en_US:qwerty";
@Entry(category = MISC, name = "Debug") public static boolean debug = false;
@Entry(category = MISC, name = "Excluded Keybindings") public static List<String> excludedKeybindings = Lists.newArrayList("key.forward", "key.left", "key.back", "key.right", "key.jump", "key.sneak", "key.sprint", "key.inventory",
"key.swapOffhand", "key.drop", "key.use", "key.attack", "key.chat", "key.playerlist", "key.screenshot", "key.togglePerspective", "key.smoothCamera", "key.fullscreen", "key.saveToolbarActivator", "key.loadToolbarActivator",

View File

@@ -0,0 +1,16 @@
package eu.midnightdust.midnightcontrols.client;
import eu.midnightdust.midnightcontrols.client.virtualkeyboard.KeyboardLayoutManager;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.SynchronousResourceReloader;
public class MidnightControlsReloadListener implements SynchronousResourceReloader {
public static final MidnightControlsReloadListener INSTANCE = new MidnightControlsReloadListener();
private MidnightControlsReloadListener() {}
@Override
public void reload(ResourceManager manager) {
manager.findResources("keyboard_layouts", path -> path.toString().startsWith("midnightcontrols") && path.toString().endsWith(".json")).forEach(KeyboardLayoutManager::loadLayout);
}
}

View File

@@ -8,35 +8,32 @@ import java.util.List;
public class KeyboardLayout {
public static KeyboardLayout QWERTY = new KeyboardLayout("US (Qwerty)", "en-US", createQwertyLetterLayout(), createSymbolLayout());
public static final List<KeyboardLayout> KEYBOARD_LAYOUTS = new ArrayList<>();
public static KeyboardLayout QWERTY = new KeyboardLayout("en_US:qwerty", createQwertyLetterLayout(), createSymbolLayout());
private final String name;
private final String locale;
private final String id;
private final List<List<String>> letters;
private final List<List<String>> symbols;
private KeyboardLayout(String name, String locale, List<List<String>> letters, List<List<String>> symbols) {
this.name = name;
this.locale = locale;
private KeyboardLayout(String id, List<List<String>> letters, List<List<String>> symbols) {
this.id = id;
this.letters = letters;
this.symbols = symbols;
}
public KeyboardLayout fromJson(JsonObject json) {
public static KeyboardLayout fromJson(JsonObject json) {
try {
return new KeyboardLayout(json.get("metadata").getAsJsonObject().get("name").getAsString(), json.get("metadata").getAsJsonObject().get("locale").getAsString(), getFromJson(json, true), getFromJson(json, false));
return new KeyboardLayout(json.get("id").getAsString(), getFromJson(json, true), getFromJson(json, false));
} catch (Exception e) {
throw new RuntimeException("Error loading keyboard definition: %s".formatted(e));
}
}
public List<List<String>> getFromJson(JsonObject json, boolean letters) {
private static List<List<String>> getFromJson(JsonObject json, boolean letters) {
String type = letters ? "letters" : "symbols";
List<List<String>> arr = new ArrayList<>();
if (json.has(type)) {
JsonObject lettersJson = json.get(type).getAsJsonObject();
for (int i = 0; ; i++) {
if (!lettersJson.has("row%s".formatted(i))) break;
if (!lettersJson.has("row"+i)) break;
var rowJson = lettersJson.get("row%s".formatted(i)).getAsJsonArray();
List<String> row = new ArrayList<>();
for (int j = 0; j < rowJson.size(); j++) {
@@ -51,12 +48,8 @@ public class KeyboardLayout {
}
}
public String getName() {
return name;
}
public String getLocale() {
return locale;
public String getId() {
return id;
}
public List<List<String>> getLetters() {

View File

@@ -0,0 +1,27 @@
package eu.midnightdust.midnightcontrols.client.virtualkeyboard;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import net.minecraft.resource.Resource;
import net.minecraft.util.Identifier;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class KeyboardLayoutManager {
private static final Map<String, KeyboardLayout> KEYBOARD_LAYOUTS = new HashMap<>();
public static void loadLayout(Identifier id, Resource resource) {
try {
JsonObject json = JsonParser.parseReader(resource.getReader()).getAsJsonObject();
KeyboardLayout layout = KeyboardLayout.fromJson(json);
KEYBOARD_LAYOUTS.put(layout.getId(), layout);
if (MidnightControlsConfig.debug) System.out.printf("Loaded keyboard layout: %s\n", layout.getId());
} catch (IOException e) { throw new RuntimeException(e); }
}
public static KeyboardLayout getById(String id) {
return KEYBOARD_LAYOUTS.get(id) == null ? KeyboardLayout.QWERTY : KEYBOARD_LAYOUTS.get(id);
}
}

View File

@@ -1,6 +1,8 @@
package eu.midnightdust.midnightcontrols.client.virtualkeyboard.gui;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.virtualkeyboard.KeyboardLayout;
import eu.midnightdust.midnightcontrols.client.virtualkeyboard.KeyboardLayoutManager;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text;
import org.thinkingstudio.obsidianui.Position;
@@ -42,10 +44,10 @@ public class VirtualKeyboardScreen extends SpruceScreen {
private SpruceContainerWidget keyboardContainer;
public VirtualKeyboardScreen(String initialText, CloseCallback closeCallback, boolean newLineSupport) {
super(Text.literal("Virtual Keyboard"));
super(Text.translatable("midnightcontrols.virtual_keyboard.screen"));
this.buffer = new StringBuilder(initialText);
this.closeCallback = closeCallback;
this.layout = KeyboardLayout.QWERTY;
this.layout = KeyboardLayoutManager.getById(MidnightControlsConfig.keyboardLayout);
this.capsMode = false;
this.symbolMode = false;
this.newLineSupport = newLineSupport;
@@ -187,7 +189,7 @@ public class VirtualKeyboardScreen extends SpruceScreen {
}
private void addFunctionKeys(SpruceContainerWidget container) {
List<String> firstRow = getActiveKeyLayout().get(0);
List<String> firstRow = getActiveKeyLayout().getFirst();
int firstRowWidth = calculateRowWidth(firstRow);
// position backspace at the right of the first row
@@ -239,7 +241,7 @@ public class VirtualKeyboardScreen extends SpruceScreen {
Position.of(spaceX, rowY),
spaceKeyWidth,
KEY_HEIGHT,
Text.literal("Space"),
Text.translatable("midnightcontrols.virtual_keyboard.keyboard.space"),
btn -> handleKeyPress(SPACE_SYMBOL)
)
);