Repository navigation
Conversation
|
@LeanBitLab Can you test this, or make test apk just for me to test it? You don't have to merge it for next version till it's tested, i want to polish this delete gesture as my last request (it shouldn't be broken like it was back then at version 429-7 , but will test it just in case). This should also solve all those previous issues i found while using your 2D solution. Sorry for troubling you with this same issue and thank you |
|
Sending
|
|
Thanks for these detailed explanation of issues, i'll try update this PR if it's possible to solve all those you mentioned |
PR #702 update: exact visual lines as an opt-in setting, review points addressedReplaces the previous version of this change. Based on current What changed since the first versionThe review comment listed three problems with sending
Everything from the previous version stays: positions found by the editor are cached Files
What this does not solve
Not verifiedNot compiled and not run (no Android toolchain available to me). Please test with the setting on, in a |
|
I think this is my last attempt for this, as Claude couldn't find any better solution (it gave me few, but none of them gives this close fix as this one, all of them have one or another issue), so if this doesn't work, or you dislike this solution, you can close this PR and keep your current 2D solution with 40 characters, it's better than nothing (not saying that your solution is bad, it's good, but thought if we can improve it), i won't trying any new methods, only previous thumb drift fix can stay |
|
It still causing these issues
|
|
In that case i'll close this PR, but tell me do you want me to try with requestTextBoundsInfo (as mentioned in this PR comment as alternative method)? It should fix all of your issues mentioned for this previous method, as that requestTextBoundsInfo won't using DPAD or any combinations of different functions. Drawbacks of using that method are that it only works from Android 14, and only if editor(s) implements it (i just googled and Chromium based browser should support it). Because of these drawbacks i didn't consider that method, and that's why i said for this previous method that is my last one to try, but if you want, we can try that requestTextBoundsInfo (and it would be seriously my last one, i asked 2 different Claude chats on 2 different accounts, and both couldn't come up with any new methods or ideas for this implementation of exact vertical cursor deleting) |
|
Let me research it further, there will be always an way |
|
Hello, i just tested your latest update, but it's not ideal solution: Screen_Recording_20261022_103902_NotallyX.mp4Screen_Recording_20261022_105921_NotallyX.mp4There's fix for it, but even with that fix i still find your previous 2D 40 characters solution better than this, so here's what i was told: "Hi, I tested 4.2.9 and found a regression in the vertical delete swipe: when the text has no sentence punctuation (. ! ? … : ;), the first swipe up selects everything up to the start of the paragraph (video attached, the text is one long paragraph of random letters). It looks like findSegmentBreaksBackwards only breaks on punctuation, so without any it returns no breaks and the whole paragraph becomes one “line”. The previous version broke at whitespace about 40 characters back, which handled this case. A possible fix is in the attached leantype-segment-breaks-fix.md: only look for punctuation in the last ~80 characters, and if none is found, fall back to the old behaviour (whitespace about 40 chars back, hard break if there is none). It includes the full function and three unit tests. I haven’t compiled it, I only checked the logic separately. Even with this fix, the vertical swipe stays an estimate. It doesn’t know the width of the field, the font, or where the editor actually wraps lines, so a swipe up moves by a sentence or about 40 characters, not by a real visual line. Only the editor knows its real line breaks. requestTextBoundsInfo (Android 14+) would fix that part. The editor tells the keyboard where its lines break, asynchronously, so there are no key events, no focus loss, no blocking calls and no shadow selection. Where the editor doesn’t support it, or on older Android, it would fall back to your current estimate. I already have an implementation, opt-in and off by default, but it is not compiled or tested on a device yet. Would you like me to send you the files, or open a draft PR? Or would you rather skip it, that’s fine too." leantype-segment-breaks-fix.md So if you want, i can later make PR with requestTextBoundsInfo which will have your previous method as fallback (here's example in real scenario where i just now tried to delete part of this message, to not be as that i only tried on random letters: Screen_Recording_20261022_111011_Brave.mp4) |
|
yup it kinda broken now, the more we tried to make it complicated the less stable it become or for normal operations |
|
maybe we should better simplify it |
|
I still think simple solution would be to implement requestTextBoundsInfo with fallback being your previous method: "I still think a more stable direction is requestTextBoundsInfo, with the old 2D 40-character estimate as the fallback. That would also mean reverting findSegmentBreaksBackwards to the previous whitespace-based estimate (the one before 4.2.9), since the sentence-punctuation logic is what breaks on text without punctuation. If you prefer to keep the new logic, the fix I attached earlier would work too, but reverting is the simpler option. How requestTextBoundsInfo would work: on the first vertical step the keyboard asks the editor once, asynchronously, for the character bounds of the lines above the cursor, turns them into line starts and uses them instead of the estimate. The selection is still set with the same plain setSelection as now. No key events, no synchronous calls, no extra selection state. If the editor doesn’t answer (older Android, unsupported editor, timeout), the behaviour is exactly the old estimate, so a failure can’t make it worse than before. It would be opt-in. Limits: Android 14+ only and it depends on the editor supporting it. I haven’t tested it on a device yet, so I’d open it as a draft for you to look at, not as something ready to merge." |
|
I'll make PR once i be home, but in case you can't wait that long: leantype-textboundsinfo-4.2.9.zip leantype-textboundsinfo-report.md It includes both bringing back your previous stable (and good) method and adding requestTextBoundsInfo (which is optional and turned off by default) Edit: i uploaded new files with only change being that option in setting is only visible for Android 14+ users, but of course your previous method stays for those who are under Android 14 |
Related: LeanType issue #467. Based on current
main(same source as beta-429-9).Problem
Swiping up on the delete key selects "lines" using
getLineBoundariesBackwards(), whichdoes not know the real layout of the text field: it splits on
\nand cuts longersegments into chunks of roughly 40-50 characters. These guessed boundaries rarely match the
real soft-wrapped lines, so after an upward step the selection starts at an arbitrary word
somewhere in the previous line.
An earlier attempt (beta-429-7) asked the editor to do the movement with Shift+DPAD_UP on a
reversed selection (anchor = right end, extent = left end). The recording attached to the issue
shows it broken: the selection would not go further than the second line above, and it flickered
in that line when swiping up again. That approach was reverted in beta-429-8.
Likely cause (found by reading the code, not confirmed on a device): an editor reports a reversed
selection to the IME as
selStart = anchor,selEnd = extent, sonewSelStart > newSelEnd.InputLogic.onUpdateSelection()passes these values toresetCachesUponCursorMoveAndReturnSuccess(), which stores them inmExpectedSelStart/Endwithout normalising. The delete swipe then sees
deleteSwipeInitialEnd != expectedSelectionEndat the next move event, re-initialises its state from the wrong values and the selection jumps back,
which looks like a stall plus flicker. This change never creates a reversed selection.
Approach
Let the editor find the position one visual line above, but with plain events and without
changing the selection logic:
send a plain DPAD_UP key event (the same events the toolbar arrow keys already send) and read
the new caret position back with
getExtractedText(synchronous).deleteSwipeLineBoundaries(index 0 = where the swipe started,index n = left end after n upward steps, same column as the arrow key gives).
up and down always return to exactly the same positions and never go below the original
start.
part (
deleteSwipeCharOffset/deleteSwipeWordIndex) relative to the entry for the current line,so up + left (diagonal) simply adds characters/words left of the exact position above.
beginBatchEdit()/endBatchEdit(), so the editorreports only the final selection to the IME. The temporary selections are always collapsed or in
normal order (start <= end), never reversed.
Everything else already in main keeps working unchanged: right-swipe deselection after a vertical
swipe (
deleteSwipeSelectionAnchor()is stillboundaries[0], the swipe start), the word-modeforward boundaries, and the thumb-drift filter in
PointerTracker.ktfor a right swipe after a left swipe(
PointerTracker.ktis not modified).Changes
KeyboardActionListenerImpl.ktdeleteSwipeApproxLineBoundaries,deleteSwipeUseEditorLines,deleteSwipeEditorTopReached(initialised when a swipe starts, cleared in
onUpWithDeletePointerActive()andresetMetaState()).onMoveDeletePointer()extends the boundaries for upward steps before the existing char/word code runs.extendDeleteSwipeLinesByEditor()andeditorPositionOneLineUp().extendLineBoundaries(boundaries, targetIndex, oneLineUp)(pure, unit tested) andLineExtendResult { REACHED, TOP, FAILED }.RichInputConnection.kt: newgetEditorSelection()(synchronousgetExtractedText, asks only for awindow of 10240 chars so large fields are not copied completely).
WordDeleteSwipeTest.kt: 5 new tests forextendLineBoundarieswith a fake editor (extends one line at atime, does not call the editor if the entry exists, stops at the top of the text, reports failure,
keeps entries found before a failure).
Fallbacks
approximation (an up arrow in a single-line field could move focus).
boundaries (
getLineBoundariesBackwards) are used for the rest of that swipe.Not verified
Not compiled and not run (no Android toolchain available to me). Please test on a device in:
a native EditText, a web textarea (Chrome/Brave), and a field with very long soft-wrapped lines with no spaces
(like the one in the beta-429-7 recording), each in char mode and word-by-word mode: