slate icon indicating copy to clipboard operation
slate copied to clipboard

The first letter is typing twice on Android

Open dudtjr913 opened this issue 1 year ago • 11 comments

Description When I type Korean in Android, the first letter is entered twice. You can also check it on slate-react example. You can check it by changing the device to Android in developer tools and then refreshing.

Recording works fine on pc

https://github.com/ianstormtaylor/slate/assets/64782636/fcad5f8e-e0cd-4b4c-a2b1-ab55aa8d4449

but doesn't work on android

https://github.com/ianstormtaylor/slate/assets/64782636/f1179ce5-70b5-4bfe-8d5b-1495443393bc

Steps To reproduce the behavior:

  1. Go to slate-react-example
  2. open developer tools
  3. Change Android device
  4. Refresh
  5. Typing
  6. See the twice typing

Expectation it should be typed only once.

Environment

  • Slate Version: "slate": "^0.94.1", "slate-history": "^0.93.0", "slate-hyperscript": "^0.77.0", "slate-react": "^0.98.0",
  • Operating System: [e.g. MAC]
  • Browser: [e.g. Android, Chrome]

dudtjr913 avatar Jul 31 '23 15:07 dudtjr913

I reproduce this behaviour when composing Chinese Characters in the same env

lauigi avatar Sep 04 '23 16:09 lauigi

We are also facing this problem

rnike avatar Sep 21 '23 08:09 rnike

This is also happening when compose in English

https://github.com/ianstormtaylor/slate/assets/48589760/144e7774-68e2-4938-aeab-590dd9ab9265

rnike avatar Sep 28 '23 04:09 rnike

Digging into the source code

When the issue occur, the Range.isCollapsed(at) returns true at line 74 in text.ts below https://github.com/ianstormtaylor/slate/blob/0bdff51a081652000ffa707a15c8878e25d8d357/packages/slate/src/interfaces/transforms/text.ts#L74-L90 At this moment the offset of anchor and focus from at is both 1 which is unexpected, should be 0 for anchor and 1 for focus

// should be
{
  anchor: {
    path: [3, 0],
    offset: 0,
  },
  focus: {
    path: [3, 0],
    offset: 1,
  },
}

// but is 
{
  anchor: {
    path: [3, 0],
    offset: 1, <- this is incorrect
  },
  focus: {
    path: [3, 0],
    offset: 1,
  },
}

The variable at is from getDefaultInsertLocation https://github.com/ianstormtaylor/slate/blob/0bdff51a081652000ffa707a15c8878e25d8d357/packages/slate/src/interfaces/transforms/text.ts#L67

Don't know if is something wrong with the normalization

rnike avatar Sep 28 '23 06:09 rnike

Update, I print out the apply operation from editor below

Screen Shot 2023-09-28 at 2 52 00 PM

it seems like there is missing the set_selection operation at the second try

rnike avatar Sep 28 '23 06:09 rnike

Update, I print out the apply operation from editor below

Screen Shot 2023-09-28 at 2 52 00 PM

it seems like there is missing the set_selection operation at the second try

Found out it might be an issue from AndroidInputManager, because the following if statement is false and will not trigger Transforms.select(editor, range) when it is going to have duplicated letters

https://github.com/ianstormtaylor/slate/blob/0bdff51a081652000ffa707a15c8878e25d8d357/packages/slate-react/src/hooks/android-input-manager/android-input-manager.ts#L178-L180

rnike avatar Oct 02 '23 01:10 rnike

Maybe we need help from @BitPhinix, the author of AndroidInputManager

rnike avatar Oct 05 '23 06:10 rnike

Saw this workaround at handleDOMBeforeInput

https://github.com/ianstormtaylor/slate/blob/0bdff51a081652000ffa707a15c8878e25d8d357/packages/slate-react/src/hooks/android-input-manager/android-input-manager.ts#L636-L658

Seems like we need another workaround to modify the start and end position, for example

             } else if (type === 'insertCompositionText') {
              if (_text.length !== _diff.end - _diff.start + 1) {
                _diff.start = _diff.end - _text.length + 1

                if (_diff.start < 0) {
                  const offset = Math.abs(_diff.start);
                  _diff.start += offset;
                  _diff.end += offset;
                }

                insertPositionHint = null;
                scheduleFlush();
              } else {
                insertPositionHint = false;
              }
            } 

NOTE: Workaround above has side effects and cannot be used in production.

rnike avatar Oct 05 '23 09:10 rnike

Does this code change fix the behaviour? Will it be integrated into slate-react?

enex avatar Mar 27 '24 05:03 enex

Facing the issue with Japanese IME too. First try of the fix above is not working. I'll investigate a bit more

Climbatize avatar Apr 10 '24 12:04 Climbatize

Sorry my bad, the workaround above has side effects and cannot be used in production, I'm just trying to declare the position issue from the editor.

rnike avatar May 22 '24 00:05 rnike