Samsung Keyboard within Android WebView causes a spam of new lines

Hi!

I was about to post this in the GitHub issues, but found out that the issue happens on a regular contenteditable without ProseMirror too.

I will post it here to ask for advice, and leave this info for others that might be experiencing this problem.

Would ProseMirror be able to work around this issue? From your experience, what would be the best place to report it?

Videos

Samsung keyboard WebView contenteditable bug report - Watch Video

Repro with ProseMirror - Watch Video

Steps to reproduce with ProseMirror

  1. Open an Android WebView (e.g. Bing, Opera, Brave, Edge)
  2. Navigate to https://prosemirror.net
  3. Put caret at the end of the second line
  4. Set your keyboard to the Samsung Keyboard
  5. Observe that new lines get added

It does not reproduce on mobile Chrome or Firefox, or when using Gboard.

Steps to reproduce without ProseMirror

  1. Open an Android WebView (e.g. Bing, Opera, Brave, Edge)
  2. Open a page with a contenteditable containing <p> or any other HTML other than <div> (see first video)
  3. Set your keyboard to Samsung Keyboard
  4. Write text using suggested next words, and some new lines
    More common for regular users would be to just get the autocorrection working
  5. Observe that new lines get added in your text. Additionally HTML text formatting gets cleared

Quick way:

Related keyboard events

There are input events unique for the moment of when the issue is reproduced. beforeinput, textInput events containing the whole text with \n are observed. (in the videos above) In Chrome - where there is no repro - I do not observe those events.

e.g. 'Like this one!\n\nTry it out by typing in here or see more examples.\n\n'


My environment

  • WebView: Android WebView 110
  • OS: Android 13, One UI 5.0
  • Device: Samsung Galaxy A52, but it happens on various Samsung devices
  • userAgent example: Mozilla/5.0 (Linux; Android 13; SM-A525F Build/TP1A.220624.014; ) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/95.0.4638.69 Mobile Safari/537.36 BingSapphire/24.1.410205314
1 Like

Thanks for digging into this to such an extent! I hadn’t seen this one yet, but there have been somewhat similar text-duplication issues with GBoard. The fact that it happens in a plan contentEditable element as well suggests that it’s probably not triggered by ProseMirror doing anything weird, so I don’t expect it can be fixed in ProseMirror, except with really bad kludges that try to detect when something like this happens and then revert it. But those always cause secondary issues (false positives, etc) so I really don’t like adding them.

Reporting the bug to Samsung might, eventually, get this fixed, but it seems the bigger the company the longer the response time on stuff like this, so that probably also won’t help a lot.

That’s right - the core reason of this issue is outside of ProseMirror


I can only imagine that it must be a headache.

This issue is terrible TBH, lots of users are reporting it, because it happens for every default Samsung setup in a few browsers, and within apps with a WebView (Samsung Internet too). It’s already 6 weeks old, so it might we worth giving it a shot.

In this case it would be maybe an option to check:

  • When a single beforeinput (or textInput) event contains "\n\n" at the end
  • AND the data is exactly the same as full current of .innerText + two additional new lines at the end "\n\n"
  • AND it’s Android
  • AND maybe some nodes check or selection check to distinguish from other events

Then preventDefault so it doesn’t get to input event if possible. If not, undo the changes.

I guess I could somehow hook up to ProseMirror, or just the events on my contenteditable and do it locally in my app?

I have managed to create a workaround for the Samsung Keyboard issue on my side. I tested this a bit, and it works for contenteditable prosemirror.net demo and my ProseMirror usage.

Feel free to use it if you encounter the issue yourself. Note that the fix is fragile and might stop working with new Samsung Keyboard update. Hopefully it won’t be needed soon.

@marijn let me know if you have any comments to the code below, and feel free to use it in ProseMirror if you wish. I’ll update this post if it doesn’t pass QA.

if (navigator.userAgent.includes("Android")) {
  const isSamsungKeyboardNewlineBugEvent = (event) => {
    // First, light checks to avoid heavy DOM reads

    const target = event.target;
    const newText = event.data;

    const isPotentiallySamsungKeyboardBugEvent =
      target.isContentEditable && 
      event.inputType === "insertText" &&
      !event.isComposing &&
      newText &&
      newText.endsWith("\n\n"); // very specific for this Samsung Keyboard bug

    if (!isPotentiallySamsungKeyboardBugEvent) {
      return false;
    }

    // Then, potentially heavier checks reading the DOM

    // While the Samsung Keyboard bug happens (in our ProseMirror case), the whole text is selected.
    // In case of other `contenteditable`s, this might not be the case, but we want to narrow it down as much as possible,
    // to avoid preventing events that user actually meant.
    const selection = document.getSelection();
    if (selection.rangeCount === 1) {
      const range = document.getSelection().getRangeAt(0);
      const isNoTextSelected = range.collapsed === true;
      if (isNoTextSelected || range.startOffset !== 0) {
        return false;
      }
    }

    // Samsung Keyboard bug event changes the number of line breaks,
    // but rest is the same as existing .innerText (not the same as .textContent!)
    const existingText = target.innerText;
    return (
      existingText.length > 0 &&
      existingText.replace(/\n/g, "") === newText.replace(/\n/g, "")
    );
  };

  // You can also attach it to a contenteditable instead.
  document.addEventListener("beforeinput", (event) => {
    if (isSamsungKeyboardNewlineBugEvent(event)) {
      event.preventDefault();
    }
  });
}

We use Froala and not ProseMirror (though it looks great!) and we’re getting killed by this issue. We originally thought it was Froala-specific, but I tried a different editor and we’re still seeing the same problem, which led me here.

I really hope Samsung fixes this – we saw it months ago and it seemed to resolve itself now it’s reared its head again.

I have an update to the code above, and I’ve put it into a gist for easier updates, feel free to use in your own project to hack-fix this issue:

1 Like

@Johny thank you so much, I can confirm this issue is not on android 10,11,12, looks like it started on 13

@Johny after a deep investigation, it looks like the issue is with Grammarly actually!, version 13 suggest text corrections are based on Grammarly. can be fixed by Samsung Keyboard → Suggest text corrections → Manage apps → turn off your app or turn them all

So I think the best solution will be to ignore somehow Grammarly on the contenteditable div

@marijn maybe Grammarly will be better on fix this

Nice find!

I’ve reported this to Grammarly support right now.

I’m not sure if there is a Grammarly process doing anything directly, or is it the Samsung Keyboard using the Grammarly service under the hood, and then causing input in conjunction with WebView contenteditable.

I can’t test it right now, but I wonder if it happens with this Grammarly keyboard too.
EDIT: It does not reproduce with Grammarly keyboard, it doesn’t touch the HTML contents even if middle of the sentence gets changed by Grammarly.

Either way, I’m going to use the hack-fix above for now until they fix it. :slight_smile:

1 Like

Grammarly has a long history of breaking editors by doing crude things to the DOM, so I’m not super surprised there. It doesn’t seem possible to install the Samsung virtual keyboard on a non-Samsung phone, making this tricky to test for me (there are apps called Samsung Keyboard in the store, but they look like obvious fakes). Thanks for posting a kludge. Ideally the software causing this, whether it’s the virtual keyboard or grammarly, gets its act together, but if not I guess it might be necessary to add the kludge to the core.

Thanks for the dialog everyone!

@Johny thanks for that fix! I gave it a try on our side but unfortunately, we’re still seeing it occur. Still investigating why; we’re seeing this in our mobile app, which uses a WebView, so that could have something to do with it.

@GuySerfaty nice find! I am definitely going to give this a try.

On another subject, I have a support ticket open with Samsung, so maybe they will pressure Grammarly (or maybe not :laughing:) if that is :100: the problem.

I’m getting reports in CodeMirror issue #1087 that an update to Samsung Keyboard might fix this. If one of you can reproduce this, could you see if it still happens with the very latest version? (All Samsung devices in my house refuse to upgrade the keyboard to a recent version, unfortunately.)

@jdixon Add some logs in the fix and see whether the selection matches when the problem reproduces. If not, remove the selection checking piece of code. :slight_smile: Use the code from gist, not the code I’ve posted here - it missed some scenarios.

@marijn great to see that! For some reason I’m stuck at 5.6.00 (can still reproduce) and can’t install 5.6.10 which is mentioned there.

@Johny yep – working on that now!

@marijn I also can’t get past 5.6.00.51, which was evidently released yesterday (March 2, 2023). The issue is still present.

Hey everyone – I spoke with Samsung and they said it’s a known issue with One UI. Fortunately, updating to One UI 5.1 appears to fix it. Let me know if updating solves it for you as well!

1 Like

Hi, I’m one of Trix developers and just wanted to mention that we found the same issue in Trix. Definitely not related to any particular editor, but caused by Samsung’s awful contenteditable support.

We ended up adding some code to detect when the Samsung keyboard starts and ends that flurry of broken events.

Hope that helps!