-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Android-Samsung keyboard] Enter two or three spaces quickly, then the editor writes backwards #13994
Comments
@ckeditor/qa-team could you check this behavior on the newest version? |
@Witoso I can confirm it still reproduces on latest docs (checked here: https://ckeditor.com/docs/ckeditor5/latest/examples/builds-custom/full-featured-editor.html, on Chrome@Android 11) |
I just retested this in the Mobile friendly editor demo and in our documentation the issue is no longer reproducible. Here's my testing setup: Device: Samsung Galaxy A52s 5G Could you try reproducing the issue now @uaza? Recently, we've been able to confirm that a couple of other issues regarding typing on Android have been fixed and it looks like this one is fixed as well. |
Here's a recording of the issue no longer being reproducible: android_typing.mp4 |
Thank you for testing. I just retested the bug with the "Mobile friendly editor demo" as well and it is still reproducible on my end. Based on your description, I was able to determine the difference and the cause. You use the "Gboard" keyboard, I use the Samsung keyboard. Also, the Samsung keyboard has the "Predictive text" switch enabled in the keyboard settings. If you turn off this switch, the bug does not occur. I hope this information helps you to narrow down and fix the bug. |
One addition that might be interesting. If you have reproduced the bug with the Samsung keyboard once and then switch to the GBoard keyboard, the input does not work properly anymore. Only a reload of the page eliminates the bug again. |
While working on #14567, I came around a second type of issue that I dubbed the “double duplication bug”. Typing after two consecutive spaces causes the typed-in character to appear twice to the right of the caret. The next keystroke will again be duplicated twice to the right, with the content in front of the caret remaining unmodified. Every keystroke afterwards will behave as normal. On the surface this sounds like something completely different but after some testing I noticed something that makes be believe that this is effectively just a different symptom of the same exact problem. I’m using a modified version of
Notice that the Using Composition Events to Suppress “Echo Events”I then set up a logic to report and suppress the Interestingly, when I suppress those “echo events”, the “double duplication bug” results in this:
Every keystroke afterwards is added to the left of the caret. The eagle-eyed among you might have spotted the two underscores present in line 3. This is something that I was previously only able to witness with a debugger breakpoint inside the One interesting tidbit: When I disable the suppression of those “echo events” and instead use a debugger breakpoint instead, I get the same exact behavior. The “echo event” never takes place when the debugger is active which is a class of heisenbugs I have witness countless times over the years when using breakpoints with How This Is Related to Reverse TypingComing back to the original issue: The reverse typing effect is a bit inconsistent, sometimes I face an even worse variant where every now and then a character appears to the left of the caret. It is worse because the next keystroke will add the keystroke to the right plus whatever is to the left of the caret. And yes, the string to the left of the caret eventually grows so that the amount of characters inserted to the right increases over and over. However, as soon as I enable the “echo event” suppression, I am no longer able to reproduce the reverse typing effect and even its evolved variant does not take place. Except, if I spam keystrokes really hard, it rarely triggers the reverse typing bug for a single letter. Final ThoughtsQuite frankly, I do not (yet) understand the nature of those extra events and what their purpose are. It feels an awful lot like I’m missing a puzzle piece here that helps me wrap my head around the composition behavior. Also, I have not yet tested how those suppressed events affect the functionality of the editor, including “external” data injections like paste events. |
Thankfully I looked into this issue too because I can only reliably reproduce this in Chrome on Android. This is closely related to the “double duplication bug” discovered in #14567, because the reverse typing is caused by a mismatch of the selection. Please read #14567 (comment) to understand what is happening, in particular the importance of the Eventually I was able to abuse Chrome’s performance profiler to figure out what causes the selection change, narrowing it down to the view renderer. One of its jobs is to sync the DOM with the expected content which for text nodes is done through Things get wild when the “reverse typing” (Chrome on Android) or “double duplication” (Firefox on Android) are being triggered. Everything looks normal until suddenly the My actual logging output is a bit more complex because I’m monitoring a lot of different states but the gist of it is this:
The two updateTextNode() calls at the end are the problem, they appear to be completely out of sync. Notice how the first one of them attempts to insert a single whitespace that comes out of nowhere and is the result of the DOM mutation event. Out of curiosity I added a switch to block the forced render inside the observer and suddenly the behavior is similar to #14567 with the difference that the last typed character appears to the right of the caret. It is different in that this is constantly updated and is not strictly the first character. So there is some merit to the mutation events, it’s just that they seem to sometimes report something that throws off the internal diff. |
So, I did check what causes the difference and it looks like the issue is caused by a mismatch of the white spaces. I did not understand how comparing I have the suspicion that there is some kind of normalization at work that favors one way over the other but breaks with the browser’s expectations. drumrolls IT WORKS. 🎉diff --git a/packages/ckeditor5-engine/src/view/renderer.ts b/packages/ckeditor5-engine/src/view/renderer.ts
index 7fa8cdff61..ccee1fe33d 100644
--- a/packages/ckeditor5-engine/src/view/renderer.ts
+++ b/packages/ckeditor5-engine/src/view/renderer.ts
@@ -1230,7 +1230,13 @@ function updateTextNode( domText: DomText, expectedText: string ) {
// @if CK_DEBUG_TYPING // );
// @if CK_DEBUG_TYPING // }
- const actions = fastDiff( actualText, expectedText );
+ const actions = fastDiff(
+ actualText,
+ expectedText,
+ ( a, b ) => {
+ return a.replace( /\u00a0/g, ' ' ) === b.replace( /\u00a0/g, ' ' );
+ }
+ );
for ( const action of actions ) {
if ( action.type === 'insert' ) { This fixes both the “double duplication” as well as the “reverse typing”. And it doesn’t stop here, I removed my workaround from #14567 (comment), thus the only thing that was left is that tiny little change above and it still works. All three types of bugs fixed with a single normalization of the white spaces during the change detection. Thinking about it, this totally makes sense. Read my previous message in this issue, in particular the part about the composition events where I noticed an odd placement of the composition indicator @Witoso @Reinmar I’m not sure if I should submit a PR at this point because I don’t understand the implications of my change above, in particular how much of an issue it is that the white spaces in the DOM and the model differ. I’m looking forward to test this change on our site, but I would really love some feedback from you guys considering how severely these two bugs impact the editing experience on Samsung Android phones. As before, I hereby release my above changes into the public domain, do whatever you want! ;-) |
This build includes the fix described in ckeditor/ckeditor5#13994 (comment)
Genius! @dtdesign respect! Thank you! |
It looks like I celebrated a bit too early, at least partly. The normalization is an important part because it prevents One possible solution would be to avoid the normalization in places that are not nearby the current composition or at least take place outside of a composition. This would allow the conversion to I’m planing to deploy a slightly modified version which applies the change to Android devices only, because the impact of the missing normalization is a somewhat acceptable tradeoff on mobile devices. Having lines sometimes wrap at an unexpected point is bad but is the lesser evil when compared to the current situation which severely breaks typing altogether. |
Restricting the workaround to This whole issue feels an awful lot like the Hydra because whenever I fix an issue a new one pops up. When I am backspacing words, the caret jumps to the end of the previous word even when there is still a trailing space. Hitting backspace once will not move the caret, but remove the space. Hitting backspace once more removes the last letter of the word. For illustration: 1, This is quite annoying and I think it has to do with the regular space ( Considering what I have learned in my journey over the past week, I am somewhat confident that #11569 is caused by the same exact problem and should be fixed by my change, because the normalization breaks the composition process. In addition, I am no longer able to reproduce #14707 with my fix, which indicates that this was indeed once more a case of a mismatch caused by the normalization of the space character. I would love to see some input from @niegowski who worked through the pain of implementing the IME support on Android in #12446 in the first place. The visual misplacement of the caret when backspacing towards a trailing regular space appears the only remaining issue, but my experience with Android is very limited. For reference, this is my current change that I am using: diff --git a/packages/ckeditor5-engine/src/view/renderer.ts b/packages/ckeditor5-engine/src/view/renderer.ts
index 7fa8cdff61..54aff6e7b1 100644
--- a/packages/ckeditor5-engine/src/view/renderer.ts
+++ b/packages/ckeditor5-engine/src/view/renderer.ts
@@ -1230,7 +1230,17 @@ function updateTextNode( domText: DomText, expectedText: string ) {
// @if CK_DEBUG_TYPING // );
// @if CK_DEBUG_TYPING // }
- const actions = fastDiff( actualText, expectedText );
+ const actions = fastDiff(
+ actualText,
+ expectedText,
+ ( a, b ) => {
+ if ( !env.isAndroid ) {
+ return a === b;
+ }
+
+ return a.replace( /\u00a0/g, ' ' ) === b.replace( /\u00a0/g, ' ' );
+ }
+ );
for ( const action of actions ) {
if ( action.type === 'insert' ) { |
I wasn’t satisfied with the misplaced caret when the text ends with a regular space ( So far it works perfectly, preserving the composition when typing and avoiding all sorts of bugs associated with the spaces. In contrast it is now able to fix the visual caret position by allowing changes that would replace a trailing regular space with diff --git a/packages/ckeditor5-engine/src/view/renderer.ts b/packages/ckeditor5-engine/src/view/renderer.ts
index 7fa8cdff61..30b9d9d0f9 100644
--- a/packages/ckeditor5-engine/src/view/renderer.ts
+++ b/packages/ckeditor5-engine/src/view/renderer.ts
@@ -1230,7 +1230,24 @@ function updateTextNode( domText: DomText, expectedText: string ) {
// @if CK_DEBUG_TYPING // );
// @if CK_DEBUG_TYPING // }
- const actions = fastDiff( actualText, expectedText );
+ let diff = ( a: string, b: string ) => a === b;
+ if ( env.isAndroid ) {
+ // This is a very crude attempt to detect backspacing at the end of the text.
+ if (
+ actualText.length > 1 &&
+ actualText.length - 1 === expectedText.length &&
+ expectedText.endsWith( '\u00a0' ) &&
+ / .$/.test( actualText )
+ ) {
+ // Do not make any change, we *want* the `\u00a0` to appear at the end.
+ } else {
+ diff = ( a, b ) => {
+ return a.replace( /\u00a0/g, ' ' ) === b.replace( /\u00a0/g, ' ' );
+ };
+ }
+ }
+
+ const actions = fastDiff( actualText, expectedText, diff );
for ( const action of actions ) {
if ( action.type === 'insert' ) { This stuff happens when people leave me unsupervised … 😉 |
This build includes the fix described in ckeditor/ckeditor5#13994 (comment)
We’re shipping this change since February 22nd and it has proven to fix this and similar issues. However, depending on the browser and keyboard this has the unwanted side-effect of preserving @Witoso I’m a bit concerned about the lack of feedback from you guys. I mean I get it, these things take time but this is an almost 1 year old bug report that severely impacts the writing experience on Android. It’s not like this is an isolated case for a niche feature, we’re talking about messing up everything when typing two consecutive spaces which can easily be the result of “fat-fingering” the space bar. Some of these bugs are reproducible with Google Chrome and GBoard, it doesn’t get more standard than that. Even in Poland the stats read something like 80%+ marketshare of Android, I really don’t understand how this gets prioritized so low. Your last feedback about this kind of issue was in December stating that you need to source some testing devices but that was is it. In early February we simply ordered a cheap Android phone from Amazon and started digging into this issue plus finding a (somewhat reasonable) workaround. We even had to dig deep into the inner workings of CKEditor to even understand what is going on, it should take experienced developers like you have a fraction of the time to get to this point. If you need more time to figure out a solution then at least let everybody know, or if you need more help then just speak up, this is an open source project after all! 🙂 |
Hi! Thanks for the ping, I’m glad the fix worked for you and solved the issue for your app. We will for sure take a look at your research. I don’t want to go into the weeds of the prioritizing things on our side. The typing has a massive splash zone of risk, and we deliberately want to schedule time for this. Even reading and analyzing your proposed solution would take significant time. But we do discuss it internally as we are aware of the impact. Another project that has considerable impact on the project, and is in progress, is #15502, defocusing from it right now would be too risky to do. We decided to go fully into it, finish, and only then move to other things. We will update this issue accordingly when we start working on it. |
We are taking a look at the #16106 issue, although unrelated, we plan to spend time on investigating this one as well. |
Fix (typing, engine): Predictive text should not get doubled while typing. Closes #16106. Fix (engine): The reverse typing effect should not happen after the focus change. Closes #14702. Thanks, @urbanspr1nter! Fix (engine, typing): Typing on Android should avoid modifying DOM while composing. Closes #13994. Closes #14707. Closes #13850. Closes #13693. Closes #14567. Closes: #11569.
Fix (typing, engine): Predictive text should not get doubled while typing. Closes ckeditor#16106. Fix (engine): The reverse typing effect should not happen after the focus change. Closes ckeditor#14702. Thanks, @urbanspr1nter! Fix (engine, typing): Typing on Android should avoid modifying DOM while composing. Closes ckeditor#13994. Closes ckeditor#14707. Closes ckeditor#13850. Closes ckeditor#13693. Closes ckeditor#14567. Closes: ckeditor#11569.
📝 Provide detailed reproduction steps (if any)
✔️ Expected result
The editor inserts the text in the correct order.
❌ Actual result
The editor insert the text backwards. Subsequently, deleting the text also does not work properly and skips some letters.
📃 Other details
Alignment,
AutoImage,
Autoformat,
AutoLink,
BlockQuote,
Bold,
Code,
CodeBlock,
Essentials,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
Heading,
HorizontalLine,
Image,
ImageCaption,
ImageInsert,
ImageResize,
ImageStyle,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
MediaEmbed,
Mention,
Paragraph,
PasteFromOffice,
RemoveFormat,
Strikethrough,
Subscript,
Superscript,
Table,
TableCellProperties,
TableProperties,
TableToolbar,
TableCaption,
TableColumnResize,
Title,
TextTransformation,
TodoList,
Underline
android_typing_backwards.mp4
If you'd like to see this fixed sooner, add a 👍 reaction to this post.
The text was updated successfully, but these errors were encountered: