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).

Reply via email to