Suppress text input for default-prevented keydown events

This is a continuation of #15266. In that pull-request we managed to
prevent IME previews from being displayed in the editor when the
originating `keydown` event was default-prevented. However, it was still
possible for IME input to make it through the previous workarounds, thus
triggering the `textInput` event and showing unwanted text.

Pressing another key that would complete the in-progress IME input
would, in fact, first replace `this.lastKeydown` and then trigger the
`textInput` event. In the handling of that event we would detect
`this.lastKeydown` as "non-default-prevented" and therefore mistakenly
insert the IME text.

With this commit we are adopting a different strategy to mitigate the
issue. When receiving the wrong `compositionupdate` event we will first
disable the hidden input and then re-enable it on the next tick.
Disabling the input causes the in-progress IME input to be aborted and
the browser to never fire `textInput` nor `compositionupdate` events
anymore after that.

The only downside of this approach is that the hidden input also loses
focus, but we transfer it back to it as soon as the next tick of the
event loop is served and the input has been re-enabled.
This commit is contained in:
Antonio Scandurra
2017-08-15 16:28:28 +02:00
parent 756dad67d8
commit 37274d3365

View File

@@ -1569,10 +1569,6 @@ class TextEditorComponent {
}
didTextInput (event) {
// Workaround for Chromium not preventing composition events when
// preventDefault is called on the keydown event that precipitated them.
if (this.lastKeydown && this.lastKeydown.defaultPrevented) return
if (!this.isInputEnabled()) return
event.stopPropagation()
@@ -1665,7 +1661,16 @@ class TextEditorComponent {
didCompositionUpdate (event) {
// Workaround for Chromium not preventing composition events when
// preventDefault is called on the keydown event that precipitated them.
if (this.lastKeydown && this.lastKeydown.defaultPrevented) return
if (this.lastKeydown && this.lastKeydown.defaultPrevented) {
this.getHiddenInput().disabled = true
process.nextTick(() => {
// Disabling the hidden input makes it lose focus as well, so we have to
// re-enable and re-focus it.
this.getHiddenInput().disabled = false
this.getHiddenInput().focus()
})
return
}
if (this.getChromeVersion() === 56) {
process.nextTick(() => {