This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new b355e41054 Fix arrow keys not working in Hop Web text fields, fixes
#7833 (#7853)
b355e41054 is described below
commit b355e41054ba97e09c582dd37b173e6543431d91
Author: Matt Casters <[email protected]>
AuthorDate: Mon Aug 10 09:08:47 2026 +0200
Fix arrow keys not working in Hop Web text fields, fixes #7833 (#7853)
Bare canvas-pan shortcuts were registered as RAP CANCEL_KEYS, so the browser
never moved the caret. Leave navigation keys active but not cancelled, and
stop HopGuiKeyHandler from stealing them inside text-like widgets.
---
.../org/apache/hop/ui/hopgui/HopWebEntryPoint.java | 23 ++++++++
.../apache/hop/ui/hopgui/HopWebEntryPointTest.java | 22 +++++++
.../org/apache/hop/ui/hopgui/HopGuiKeyHandler.java | 67 ++++++++++++++++------
3 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
b/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
index 8177382d19..352b48f105 100644
--- a/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
+++ b/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
@@ -51,9 +51,31 @@ import org.eclipse.swt.widgets.Display;
public class HopWebEntryPoint extends AbstractEntryPoint {
+ /**
+ * Shortcuts that must remain active (sent to the server) but must not be
cancelled in the
+ * browser, so native text editing still works (e.g. Ctrl+C/V/X in input
fields).
+ */
private static final Set<String> NATIVE_TEXT_EDITING_SHORTCUTS =
Set.of("CTRL+C", "CTRL+V", "CTRL+X");
+ /**
+ * Bare navigation keys used for caret movement and selection in text fields
(and tree widgets).
+ * They may stay in {@code ACTIVE_KEYS} so canvas pan shortcuts still reach
the server when focus
+ * is on the graph, but must not be in {@code CANCEL_KEYS} or the browser
never moves the caret
+ * (see issue #7833). Modifier combinations (CTRL+ARROW_*, ALT+ARROW_*, …)
are separate RAP keys
+ * and remain cancelled when registered as application shortcuts.
+ */
+ private static final Set<String> NATIVE_TEXT_NAVIGATION_KEYS =
+ Set.of(
+ "ARROW_UP",
+ "ARROW_DOWN",
+ "ARROW_LEFT",
+ "ARROW_RIGHT",
+ "HOME",
+ "END",
+ "PAGE_UP",
+ "PAGE_DOWN");
+
/** Audit group/type/name for Hop Web theme preference (per-user in audit
folder). */
public static final String AUDIT_GROUP_HOP_WEB = "hop-web";
@@ -346,6 +368,7 @@ public class HopWebEntryPoint extends AbstractEntryPoint {
static String[] buildCancelledKeyboardShortcuts(String[] activeShortcuts) {
return Arrays.stream(activeShortcuts)
.filter(shortcut -> !NATIVE_TEXT_EDITING_SHORTCUTS.contains(shortcut))
+ .filter(shortcut -> !NATIVE_TEXT_NAVIGATION_KEYS.contains(shortcut))
.distinct()
.toArray(String[]::new);
}
diff --git
a/rap/src/test/java/org/apache/hop/ui/hopgui/HopWebEntryPointTest.java
b/rap/src/test/java/org/apache/hop/ui/hopgui/HopWebEntryPointTest.java
index decef4fb17..60c65c1c7e 100644
--- a/rap/src/test/java/org/apache/hop/ui/hopgui/HopWebEntryPointTest.java
+++ b/rap/src/test/java/org/apache/hop/ui/hopgui/HopWebEntryPointTest.java
@@ -38,6 +38,28 @@ class HopWebEntryPointTest {
assertArrayEquals(new String[] {"CTRL+S"}, cancelledShortcuts);
}
+ @Test
+ void preservesBareNavigationKeysAsActiveOnly() {
+ // Canvas pan registers bare arrows/HOME as ACTIVE_KEYS; CANCEL would
block caret movement in
+ // text fields (issue #7833). Modifier combos stay cancellable for app
shortcuts.
+ String[] activeShortcuts = {
+ "ARROW_LEFT",
+ "ARROW_RIGHT",
+ "ARROW_UP",
+ "ARROW_DOWN",
+ "HOME",
+ "END",
+ "PAGE_UP",
+ "PAGE_DOWN",
+ "CTRL+ARROW_LEFT",
+ "CTRL+S"
+ };
+
+ String[] cancelledShortcuts =
HopWebEntryPoint.buildCancelledKeyboardShortcuts(activeShortcuts);
+
+ assertArrayEquals(new String[] {"CTRL+ARROW_LEFT", "CTRL+S"},
cancelledShortcuts);
+ }
+
@Test
void removesDuplicateCancelledShortcuts() {
String[] cancelledShortcuts =
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiKeyHandler.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiKeyHandler.java
index 673a64d24e..9d2d467c75 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiKeyHandler.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiKeyHandler.java
@@ -83,23 +83,13 @@ public class HopGuiKeyHandler extends KeyAdapter {
return;
}
- // Ignore shortcuts inside Text, Combo, StyledText, or CCombo widgets
(including terminal).
+ // Do not steal keys needed for native editing / caret movement inside
text-like widgets.
// StyledText is not available in RAP, so we check via reflection to avoid
NoClassDefFoundError.
- if (event.widget instanceof Text
- || event.widget instanceof Combo
- || event.widget instanceof CCombo
- || isStyledText(event.widget)) {
- // Ignore Copy/Cut/Paste/Select all - check both keyCode and character
- if ((event.stateMask & (SWT.CONTROL + SWT.COMMAND)) != 0) {
- char key = Character.toLowerCase((char) event.keyCode);
- if (key == 'a' || key == 'c' || key == 'v' || key == 'x') {
- return;
- }
- }
- // Ignore DEL and Backspace
- if (event.keyCode == SWT.DEL || event.character == SWT.BS) {
- return;
- }
+ // Bare ARROW_*/HOME/END would otherwise match canvas pan shortcuts
(DragViewZoomBase) and break
+ // caret navigation — especially in Hop Web where RAP CANCEL_KEYS can also
block the browser
+ // (see issue #7833). App shortcuts with CTRL/CMD/ALT (e.g. Ctrl+S,
Ctrl+Arrow) still run.
+ if (isTextLikeWidget(event.widget) && isNativeTextEditingKey(event)) {
+ return;
}
List<Object> orderedParents = getParentObjectsInContextOrder(event.widget);
@@ -279,6 +269,51 @@ public class HopGuiKeyHandler extends KeyAdapter {
return false;
}
+ /**
+ * Returns true if the widget is a Text, Combo, CCombo, or StyledText.
StyledText is resolved via
+ * reflection so it is not referenced when it is not on the classpath (e.g.
in RAP/Hop Web).
+ */
+ private static boolean isTextLikeWidget(Widget widget) {
+ if (widget == null) {
+ return false;
+ }
+ return widget instanceof Text
+ || widget instanceof Combo
+ || widget instanceof CCombo
+ || isStyledText(widget);
+ }
+
+ /**
+ * Keys that text-like widgets must handle themselves:
copy/cut/paste/select-all,
+ * delete/backspace, and caret / selection navigation (arrows, home/end,
page up/down) without
+ * CTRL/CMD/ALT. Shift alone is allowed so Shift+Arrow selection stays in
the widget.
+ */
+ private static boolean isNativeTextEditingKey(KeyEvent event) {
+ if ((event.stateMask & (SWT.CONTROL | SWT.COMMAND)) != 0) {
+ char key = Character.toLowerCase((char) event.keyCode);
+ if (key == 'a' || key == 'c' || key == 'v' || key == 'x') {
+ return true;
+ }
+ }
+ if (event.keyCode == SWT.DEL || event.character == SWT.BS) {
+ return true;
+ }
+ // Caret movement / selection: leave for the widget unless an app modifier
is held
+ boolean hasAppModifier = (event.stateMask & (SWT.CONTROL | SWT.COMMAND |
SWT.ALT)) != 0;
+ if (!hasAppModifier) {
+ int keyCode = event.keyCode & SWT.KEY_MASK;
+ return keyCode == SWT.ARROW_LEFT
+ || keyCode == SWT.ARROW_RIGHT
+ || keyCode == SWT.ARROW_UP
+ || keyCode == SWT.ARROW_DOWN
+ || keyCode == SWT.HOME
+ || keyCode == SWT.END
+ || keyCode == SWT.PAGE_UP
+ || keyCode == SWT.PAGE_DOWN;
+ }
+ return false;
+ }
+
/**
* Returns true if the widget is a StyledText. Uses reflection so that
StyledText is not
* referenced when it is not on the classpath (e.g. in RAP/Hop Web).