From 52c70e817dcd023ac5df59a892acd329ab473fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sat, 7 Nov 2026 19:03:20 +0100 Subject: [PATCH] editor: fly keys work while another component has the keyboard focus (window-wide key dispatcher during right-mouse fly), held keys cleared when the flight ends --- CHANGELOG.md | 5 +++ .../llamamod/editor/render/Viewport.java | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74267ba..7c084f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.2.3 – unreleased + +- **Editor:** flying with the right mouse button + W A S D / Q E now works even when another part of + the window (a text field, a dock) still had the keyboard focus. + ## 0.2.2 – 2026-11-07 - **English game version supported.** All exe mods (boot to level, cheats, intro skip, practice diff --git a/src/main/java/com/eliasmueller/llamamod/editor/render/Viewport.java b/src/main/java/com/eliasmueller/llamamod/editor/render/Viewport.java index ce8127f..991b78c 100644 --- a/src/main/java/com/eliasmueller/llamamod/editor/render/Viewport.java +++ b/src/main/java/com/eliasmueller/llamamod/editor/render/Viewport.java @@ -7,6 +7,8 @@ import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Graphics; +import java.awt.KeyEventDispatcher; +import java.awt.KeyboardFocusManager; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.InputEvent; @@ -93,6 +95,36 @@ public final class Viewport extends JPanel { private boolean dirty = true; private long lastTick = System.nanoTime(); private final Set keys = new HashSet<>(); + + /** + * While flying, WASD/QE/Shift reach the fly loop even if another component (a text field, a + * dock) still has the keyboard focus: with some window managers the heavyweight GL canvas does + * not get the focus from a right-click. + */ + private final KeyEventDispatcher flyKeys = e -> { + if (!this.flying) { + return false; + } + if (e.getID() == KeyEvent.KEY_PRESSED) { + keys.add(e.getKeyCode()); + } else if (e.getID() == KeyEvent.KEY_RELEASED) { + keys.remove(e.getKeyCode()); + } + return true; + }; + + @Override + public void addNotify() { + super.addNotify(); + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(flyKeys); + } + + @Override + public void removeNotify() { + KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(flyKeys); + super.removeNotify(); + } + private boolean flying; private BufferedImage capture; private boolean captureNext; @@ -1131,6 +1163,7 @@ public final class Viewport extends JPanel { } if (drag == Drag.FLY) { flying = false; + keys.clear(); // a key released after the button may have gone to another component canvas.setCursor(Cursor.getDefaultCursor()); } if (drag != Drag.NONE && buttonOf(drag, e)) {