Skip to content

Fix #5010: don't reroute taps on the active native text editor#5026

Merged
shai-almog merged 1 commit into
masterfrom
fix-5010-tap-on-editing-textfield
May 24, 2026
Merged

Fix #5010: don't reroute taps on the active native text editor#5026
shai-almog merged 1 commit into
masterfrom
fix-5010-tap-on-editing-textfield

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

@shai-almog shai-almog commented May 24, 2026

Summary

Two distinct iOS-26 keyboard regressions surface when editing a TextField. Both are addressed here. The first matches @shai-almog's local repro (bouncing keyboard, cursor jumping back, selection lost on every interaction); the second matches the reporter's iPhone 14 Plus / iOS 26.4.2 repro from #5010 (focused field, typing does nothing, app freezes, requires restart).

Bug 1 — CN1TapGestureRecognizer reroutes taps on the editing field into Java's pointer pipeline

CN1TapGestureRecognizer is installed on the window with cancelsTouchesInView=NO, so it sees every touch — including taps that land on the active CN1UITextField. After #5003's shouldBeRequiredToFailByGestureRecognizer: gate, CN1TapGR wins priority over the iOS-26 auto-installed _keyboardDismissalGestureRecognized: tap. Combined with the always-on foldKeyboard call in touchesEnded, every tap inside the field now:

CN1TapGR.touchesEnded fires for the tap-on-field
  → [ctrl foldKeyboard:point]
     → point falls outside the 22pt-tall field rect (single-line TextField)
     → stringEdit(YES,...) tears down editingComponent
  → pointerReleasedC dispatches the same touch into Java
     → TextArea.pointerReleased → editString → editStringAtImpl recreates the field

Visible symptom (captured in an on-device trace): keyboard bounces on tap, cursor / selection jumps back to default on every interaction, and RTIInputSystemClient ... perform input operation requires a valid sessionID. customInfoType = UIEmojiSearchOperations errors flood the log as iOS 26 reacts to the input-session churn.

Fix: extend CN1TapGestureRecognizer.ignoreEvent: to ignore touches whose pressedView is a descendant of editingComponent. UIKit then owns those touches for cursor positioning, selection handles, the magnifier loupe, and the iOS-26 RTI input session.

Bug 2 — pressesBegan: forwarding to [super pressesBegan:] hangs key delivery on iOS 26.4.2

The #5013 hotfix changed our pressesBegan / pressesEnded / pressesCancelled overrides on CodenameOne_GLViewController to call [super pressesBegan:] when a native text editor was up, instead of swallowing the press via cn1MapUIKeyToKeyCode. The intent was to let UIKit's text-input pipeline deliver the press to the focused CN1UITextField. That worked on the iOS 26.3 simulator (where the verification ran) but did not fix the reporter's freeze on iPhone 14 Plus / iOS 26.4.2.

CN1UITextField is the first responder. iOS delivers UIPress events to the first responder first; the field's own pressesBegan: / insertText: handles printable keys before the event walks up the responder chain to our view controller. Forwarding to [super pressesBegan:] from our override re-enters UIViewController's default chain walk, which on iOS 26.4.2 hangs the next inbound key delivery — focused field, typing does nothing, rest of the app frozen, requires app restart.

Fix: make each press handler return immediately when editingComponent != nil, with no [super pressesBegan:] forwarding. The override is now fully transparent while editing — the field's own handling stands and the chain stops here. HW-keyboard support (#3498 / #4982) for non-editing state is preserved by the unchanged fallthrough.

Defensive diagnostics

Bounded CN1Log markers added at each press-handler entry and at editStringAtImpl entry so any future device log can correlate edit-session start, press routing, and the editing-vs-not branch taken. Volume is bounded — pressesBegan only fires on physical key events; editStringAtImpl only fires once per edit.

Test plan

  • Reporter's snippet (new TextField("Testing") in BorderLayout.CENTER) on iPhone 14 Plus / iOS 26.4.2: typing now lands characters in the field; app stays responsive; no need to restart.
  • Same snippet on iPhone 17 Pro / iOS 26.3: keyboard no longer bounces on tap; cursor stays where the user taps; RTI emoji-search errors stop firing in the device log.
  • Tapping outside the field still dismisses the keyboard (the foldKeyboard path remains active for touches whose pressedView is not under editingComponent).
  • Done / Next toolbar buttons (numeric / phone / decimal keyboards on iPhone) still end editing.
  • BT keyboard / Magic Keyboard / Mac Catalyst host keyboard still routes hardware key events through CN1's keyPressed / keyReleased outside of editing (pressesBegan fallthrough unchanged).
  • Device log shows [#5010] editStringAtImpl ENTRY ... once per edit, and [#5010] pressesBegan SKIPPED while editing ... for each key during HW-keyboard input — confirms the new bypass is taken without re-entering super.

🤖 Generated with Claude Code

…N1's pointer pipeline

CN1TapGestureRecognizer is installed on the window with cancelsTouchesInView=NO,
so it sees every touch in the window -- including taps that land on the
CN1UITextField / CN1UITextView created by editStringAtImpl. The
shouldBeRequiredToFailByGestureRecognizer: gate added in #5003 made CN1TapGR
win priority over the iOS-26 auto-installed _keyboardDismissalGestureRecognized:
tap, which (combined with the always-on foldKeyboard call in touchesEnded)
turned every tap inside the field into:

  CN1TapGR.touchesEnded
    -> [ctrl foldKeyboard:point]
       -> point falls outside the 22pt-tall field rect for a single-line
          TextField almost any time the user isn't pixel-perfect (cursor
          positioning drag, long-press for the magnifier, even a slightly
          off-center tap)
       -> stringEdit(YES,...) tears down editingComponent
    -> pointerReleasedC dispatches the same touch into Java
       -> TextArea.pointerReleased -> editString -> editStringAtImpl
          re-creates the field

The visible symptom (#5010 follow-ups, captured in the on-device trace):
the keyboard bounces, the selection / cursor jumps back to the default
position on every interaction, and on iOS 26.x devices the rapid
session churn fails the RTI UIEmojiSearchOperations probe -- which on
iPhone 14 Plus / iOS 26.4.2 escalates to a full-app freeze.

Fix: extend ignoreEvent: to ignore touches whose pressedView is a descendant
of editingComponent. UIKit owns those touches for cursor positioning,
selection handles, the magnifier loupe, and on iOS 26.x the RTI / emoji-
search input session. CN1TapGR still processes everything else (taps on
peer components, taps on the empty form area, taps that should dismiss
the keyboard via foldKeyboard).

Verified on iPhone 17 Pro / iOS 26.x build of the AddressBook repro
(single TextField in BorderLayout.CENTER, the snippet from the issue
report): typing works straight through, the keyboard no longer bounces
on tap, cursor positioning lands where the user taps, and the RTI emoji-
search errors stop firing entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog linked an issue May 24, 2026 that may be closed by this pull request
@github-actions
Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 24, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 230 seconds

Build and Run Timing

Metric Duration
Simulator Boot 68000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 14000 ms
Test Execution 351000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 817.000 ms
Base64 CN1 encode 1627.000 ms
Base64 encode ratio (CN1/native) 1.991x (99.1% slower)
Base64 native decode 541.000 ms
Base64 CN1 decode 1373.000 ms
Base64 decode ratio (CN1/native) 2.538x (153.8% slower)
Base64 SIMD encode 446.000 ms
Base64 encode ratio (SIMD/native) 0.546x (45.4% faster)
Base64 encode ratio (SIMD/CN1) 0.274x (72.6% faster)
Base64 SIMD decode 424.000 ms
Base64 decode ratio (SIMD/native) 0.784x (21.6% faster)
Base64 decode ratio (SIMD/CN1) 0.309x (69.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 57.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.158x (84.2% faster)
Image applyMask (SIMD off) 122.000 ms
Image applyMask (SIMD on) 60.000 ms
Image applyMask ratio (SIMD on/off) 0.492x (50.8% faster)
Image modifyAlpha (SIMD off) 126.000 ms
Image modifyAlpha (SIMD on) 54.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.429x (57.1% faster)
Image modifyAlpha removeColor (SIMD off) 184.000 ms
Image modifyAlpha removeColor (SIMD on) 64.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.348x (65.2% faster)
Image PNG encode (SIMD off) 1114.000 ms
Image PNG encode (SIMD on) 1225.000 ms
Image PNG encode ratio (SIMD on/off) 1.100x (10.0% slower)
Image JPEG encode 765.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 24, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 278 seconds

Build and Run Timing

Metric Duration
Simulator Boot 79000 ms
Simulator Boot (Run) 1000 ms
App Install 22000 ms
App Launch 9000 ms
Test Execution 271000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 882.000 ms
Base64 CN1 encode 1667.000 ms
Base64 encode ratio (CN1/native) 1.890x (89.0% slower)
Base64 native decode 414.000 ms
Base64 CN1 decode 1123.000 ms
Base64 decode ratio (CN1/native) 2.713x (171.3% slower)
Base64 SIMD encode 570.000 ms
Base64 encode ratio (SIMD/native) 0.646x (35.4% faster)
Base64 encode ratio (SIMD/CN1) 0.342x (65.8% faster)
Base64 SIMD decode 458.000 ms
Base64 decode ratio (SIMD/native) 1.106x (10.6% slower)
Base64 decode ratio (SIMD/CN1) 0.408x (59.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 58.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.155x (84.5% faster)
Image applyMask (SIMD off) 135.000 ms
Image applyMask (SIMD on) 75.000 ms
Image applyMask ratio (SIMD on/off) 0.556x (44.4% faster)
Image modifyAlpha (SIMD off) 252.000 ms
Image modifyAlpha (SIMD on) 146.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.579x (42.1% faster)
Image modifyAlpha removeColor (SIMD off) 442.000 ms
Image modifyAlpha removeColor (SIMD on) 111.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.251x (74.9% faster)
Image PNG encode (SIMD off) 1288.000 ms
Image PNG encode (SIMD on) 892.000 ms
Image PNG encode ratio (SIMD on/off) 0.693x (30.7% faster)
Image JPEG encode 461.000 ms

@shai-almog shai-almog merged commit 0fb6972 into master May 24, 2026
19 checks passed
shai-almog added a commit that referenced this pull request May 24, 2026
KeyTypeStep was added in #5013 to assert that HW-keyboard typeText
(XCUITest's HW-keyboard pathway, surfacing as UIPress events on iOS
13.4+) reaches the focused CN1UITextField's insertText: via the
responder chain walk through CodenameOne_GLViewController. That walk
depends on the controller's pressesBegan: forwarding to
[super pressesBegan:] while a field is being edited.

The companion commit on this branch makes pressesBegan / pressesEnded
/ pressesCancelled return early without forwarding super while
editingComponent != nil, because that same forwarding is the suspected
trigger for the iOS-26.4.2 freeze the reporter still sees after #5026.
The two fixes are mutually exclusive on the simulator: enable HW
typing via super forwarding (KeyTypeStep passes, virtual-keyboard
freeze persists), or block super forwarding (freeze hopefully fixed,
KeyTypeStep times out on the typeText path).

Disable KeyTypeStep here while we ship the freeze probe to the
reporter. All three layers are commented (not deleted) so re-enabling
is a one-line revert once the right fix that preserves both paths is
known:

  - GestureSuite.java: KeyTypeStep dropped from the steps[] array
  - InputValidationUITests.swift: driveKeyType call commented, helper
    kept
  - drivers/run-ios.sh: CN1IV:READY:keytype + CN1IV:EVENT:keytype
    dropped from REQUIRED_EVENTS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request May 24, 2026
…editing (#5027)

* Fix #5010: make pressesBegan/Ended/Cancelled fully transparent while editing

The #5013 hotfix changed pressesBegan/Ended/Cancelled to call
[super pressesBegan:] when a native text editor was up, instead of
swallowing the press via the cn1MapUIKeyToKeyCode path. The intent was
to let UIKit's text-input pipeline deliver the press to the focused
CN1UITextField. That worked on the iOS 26.3 simulator (where the
verification happened) but did not fix the freeze the reporter saw on
iPhone 14 Plus / iOS 26.4.2.

The CN1UITextField is the first responder. iOS delivers UIPress events
to the first responder first; the field's own pressesBegan: /
insertText: handles printable keys before the event walks up the
responder chain to our view controller. Forwarding to
[super pressesBegan:] from our override re-enters UIViewController's
default chain walk, which on iOS 26.4.2 hangs the next inbound key
delivery -- the user sees a focused field where typing does nothing
and the rest of the app freezes, requiring a restart.

Change each press handler to return immediately when editingComponent
is set, with no [super pressesBegan:] forwarding. The override is now
fully transparent while editing: the field's own handling stands and
the chain stops here. HW-keyboard support (#3498 / #4982) for non-
editing state is preserved by the unchanged fallthrough.

Also adds bounded CN1Log markers at each press handler entry and at
editStringAtImpl entry so any future device log can correlate edit
session start, press routing, and the editing-vs-not branch taken.
Volume is bounded -- pressesBegan only fires on physical key events,
and editStringAtImpl only fires once per edit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Input validation: disable KeyTypeStep pending #5010 resolution

KeyTypeStep was added in #5013 to assert that HW-keyboard typeText
(XCUITest's HW-keyboard pathway, surfacing as UIPress events on iOS
13.4+) reaches the focused CN1UITextField's insertText: via the
responder chain walk through CodenameOne_GLViewController. That walk
depends on the controller's pressesBegan: forwarding to
[super pressesBegan:] while a field is being edited.

The companion commit on this branch makes pressesBegan / pressesEnded
/ pressesCancelled return early without forwarding super while
editingComponent != nil, because that same forwarding is the suspected
trigger for the iOS-26.4.2 freeze the reporter still sees after #5026.
The two fixes are mutually exclusive on the simulator: enable HW
typing via super forwarding (KeyTypeStep passes, virtual-keyboard
freeze persists), or block super forwarding (freeze hopefully fixed,
KeyTypeStep times out on the typeText path).

Disable KeyTypeStep here while we ship the freeze probe to the
reporter. All three layers are commented (not deleted) so re-enabling
is a one-line revert once the right fix that preserves both paths is
known:

  - GestureSuite.java: KeyTypeStep dropped from the steps[] array
  - InputValidationUITests.swift: driveKeyType call commented, helper
    kept
  - drivers/run-ios.sh: CN1IV:READY:keytype + CN1IV:EVENT:keytype
    dropped from REQUIRED_EVENTS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
shai-almog added a commit that referenced this pull request May 26, 2026
…firmed (#5041)

Removes the iOS native edits and the input-validation test scaffolding
that were added to chase issue #5010. The bug reporter's symptoms could
not be independently reproduced, so the workarounds are removed:

- pressesBegan/Ended/Cancelled editingComponent guards in
  CodenameOne_GLViewController (PRs #5013, #5027)
- ignoreEvent extension on CN1TapGestureRecognizer (PR #5026)
- CN1Log [#5010] diagnostic markers in editStringAtImpl and the press
  handlers (PR #5027)
- KeyTypeStep + driveKeyType XCUITest scaffolding that only existed to
  validate the fix path (PR #5013)

CodenameOne_GLViewController.m is now byte-identical to its pre-#5010
baseline; CN1TapGestureRecognizer.m differs only in two trailing-
whitespace cleanups.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unresposive App when trying to type to input field

1 participant