diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/KeyConverter.java b/projects/common/src/client/java/dan200/computercraft/client/gui/KeyConverter.java new file mode 100644 index 000000000..99ee64077 --- /dev/null +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/KeyConverter.java @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.client.gui; + +import org.lwjgl.glfw.GLFW; + +/** + * Supports for converting/translating key codes. + */ +public class KeyConverter { + /** + * GLFW's key events refer to the physical key code, rather than the "actual" key code (with keyboard layout + * applied). + *
+ * This makes sense for WASD-style input, but is a right pain for keyboard shortcuts — this function attempts to + * translate those keys back to their "actual" key code. See also + * this discussion on GLFW's GitHub. + * + * @param key The current key code. + * @param scanCode The current scan code. + * @return The translated key code. + */ + public static int physicalToActual(int key, int scanCode) { + var name = GLFW.glfwGetKeyName(key, scanCode); + if (name == null || name.length() != 1) return key; + + // If we've got a single character key name, try to translate it to a + var character = name.charAt(0); + + // 0-9 and A-Z map directly to their GLFW key (they're the same ASCII code). + if ((character >= '0' && character <= '9') || (character >= 'A' && character <= 'Z')) return character; + // a-z map to GLFW_KEY_{A,Z} + if (character >= 'a' && character <= 'z') return GLFW.GLFW_KEY_A + (character - 'a'); + + return key; + } +} diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java b/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java index 2bf9a4494..b2e14cd88 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java @@ -5,6 +5,7 @@ package dan200.computercraft.client.gui.widgets; import com.mojang.blaze3d.vertex.Tesselator; +import dan200.computercraft.client.gui.KeyConverter; import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; @@ -85,7 +86,7 @@ public class TerminalWidget extends AbstractWidget { } if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) { - switch (key) { + switch (KeyConverter.physicalToActual(key, scancode)) { case GLFW.GLFW_KEY_T -> { if (terminateTimer < 0) terminateTimer = 0; } @@ -121,7 +122,7 @@ public class TerminalWidget extends AbstractWidget { computer.keyUp(key); } - switch (key) { + switch (KeyConverter.physicalToActual(key, scancode)) { case GLFW.GLFW_KEY_T -> terminateTimer = -1; case GLFW.GLFW_KEY_R -> rebootTimer = -1; case GLFW.GLFW_KEY_S -> shutdownTimer = -1;