зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1810406 - Handle asynchronous composition without synthesized `GDK_KEY_PRESS` event r=m_kato
IME for ibus may send composition after filtering `GDK_KEY_PRESS` event asynchronously. In that case, IME or ibus usually synthesize `GDK_KEY_PRESS` again for letting the application know what's being handled. However, according to the bug report, IME may send composition without synthesizing the `GDK_KEY_PRESS` event. Without this patch, `IMContextWrapper` dispatches only `eContentCommandInsertText` event. Then, it'll cause only a set of `beforeinput` and `input` events. Therefore, web apps may fail to do something if they listen only composition and keyboard events only in Gecko. For avoiding Gecko only failure in this case, we should make `IMContentWrapper` handle the composition with `GDK_KEY_PRESS` event in the queue which it has not handled yet. Then, web apps can work with `keydown` events whose `key` is `"Process"`. Differential Revision: https://phabricator.services.mozilla.com/D170031
This commit is contained in:
Родитель
0df404cf45
Коммит
0dfc1d00f9
|
@ -1059,6 +1059,17 @@ KeyHandlingState IMContextWrapper::OnKeyEvent(
|
||||||
mMaybeInDeadKeySequence = false;
|
mMaybeInDeadKeySequence = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aEvent->type == GDK_KEY_RELEASE) {
|
||||||
|
if (const GdkEventKey* pendingKeyPressEvent =
|
||||||
|
mPostingKeyEvents.GetCorrespondingKeyPressEvent(aEvent)) {
|
||||||
|
MOZ_LOG(gIMELog, LogLevel::Warning,
|
||||||
|
("0x%p OnKeyEvent(), forgetting a pending GDK_KEY_PRESS event "
|
||||||
|
"because GDK_KEY_RELEASE for the event is handled",
|
||||||
|
this));
|
||||||
|
mPostingKeyEvents.RemoveEvent(pendingKeyPressEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_LOG(
|
MOZ_LOG(
|
||||||
gIMELog, LogLevel::Debug,
|
gIMELog, LogLevel::Debug,
|
||||||
("0x%p OnKeyEvent(), succeeded, filterThisEvent=%s "
|
("0x%p OnKeyEvent(), succeeded, filterThisEvent=%s "
|
||||||
|
@ -1615,6 +1626,21 @@ void IMContextWrapper::OnStartCompositionCallback(GtkIMContext* aContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMContextWrapper::OnStartCompositionNative(GtkIMContext* aContext) {
|
void IMContextWrapper::OnStartCompositionNative(GtkIMContext* aContext) {
|
||||||
|
// IME may synthesize composition asynchronously after filtering a
|
||||||
|
// GDK_KEY_PRESS event. In that case, we should handle composition with
|
||||||
|
// emulating the usual case, i.e., this is called in the stack of
|
||||||
|
// OnKeyEvent().
|
||||||
|
Maybe<AutoRestore<GdkEventKey*>> maybeRestoreProcessingKeyEvent;
|
||||||
|
if (!mProcessingKeyEvent && !mPostingKeyEvents.IsEmpty()) {
|
||||||
|
GdkEventKey* keyEvent = mPostingKeyEvents.GetFirstEvent();
|
||||||
|
if (keyEvent && keyEvent->type == GDK_KEY_PRESS &&
|
||||||
|
KeymapWrapper::ComputeDOMKeyNameIndex(keyEvent) ==
|
||||||
|
KEY_NAME_INDEX_USE_STRING) {
|
||||||
|
maybeRestoreProcessingKeyEvent.emplace(mProcessingKeyEvent);
|
||||||
|
mProcessingKeyEvent = mPostingKeyEvents.GetFirstEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_LOG(gIMELog, LogLevel::Info,
|
MOZ_LOG(gIMELog, LogLevel::Info,
|
||||||
("0x%p OnStartCompositionNative(aContext=0x%p), "
|
("0x%p OnStartCompositionNative(aContext=0x%p), "
|
||||||
"current context=0x%p, mComposingContext=0x%p",
|
"current context=0x%p, mComposingContext=0x%p",
|
||||||
|
@ -1702,6 +1728,21 @@ void IMContextWrapper::OnChangeCompositionCallback(GtkIMContext* aContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMContextWrapper::OnChangeCompositionNative(GtkIMContext* aContext) {
|
void IMContextWrapper::OnChangeCompositionNative(GtkIMContext* aContext) {
|
||||||
|
// IME may synthesize composition asynchronously after filtering a
|
||||||
|
// GDK_KEY_PRESS event. In that case, we should handle composition with
|
||||||
|
// emulating the usual case, i.e., this is called in the stack of
|
||||||
|
// OnKeyEvent().
|
||||||
|
Maybe<AutoRestore<GdkEventKey*>> maybeRestoreProcessingKeyEvent;
|
||||||
|
if (!mProcessingKeyEvent && !mPostingKeyEvents.IsEmpty()) {
|
||||||
|
GdkEventKey* keyEvent = mPostingKeyEvents.GetFirstEvent();
|
||||||
|
if (keyEvent && keyEvent->type == GDK_KEY_PRESS &&
|
||||||
|
KeymapWrapper::ComputeDOMKeyNameIndex(keyEvent) ==
|
||||||
|
KEY_NAME_INDEX_USE_STRING) {
|
||||||
|
maybeRestoreProcessingKeyEvent.emplace(mProcessingKeyEvent);
|
||||||
|
mProcessingKeyEvent = mPostingKeyEvents.GetFirstEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_LOG(gIMELog, LogLevel::Info,
|
MOZ_LOG(gIMELog, LogLevel::Info,
|
||||||
("0x%p OnChangeCompositionNative(aContext=0x%p), "
|
("0x%p OnChangeCompositionNative(aContext=0x%p), "
|
||||||
"mComposingContext=0x%p",
|
"mComposingContext=0x%p",
|
||||||
|
@ -1833,6 +1874,21 @@ void IMContextWrapper::OnCommitCompositionNative(GtkIMContext* aContext,
|
||||||
const gchar* commitString = aUTF8Char ? aUTF8Char : &emptyStr;
|
const gchar* commitString = aUTF8Char ? aUTF8Char : &emptyStr;
|
||||||
NS_ConvertUTF8toUTF16 utf16CommitString(commitString);
|
NS_ConvertUTF8toUTF16 utf16CommitString(commitString);
|
||||||
|
|
||||||
|
// IME may synthesize composition asynchronously after filtering a
|
||||||
|
// GDK_KEY_PRESS event. In that case, we should handle composition with
|
||||||
|
// emulating the usual case, i.e., this is called in the stack of
|
||||||
|
// OnKeyEvent().
|
||||||
|
Maybe<AutoRestore<GdkEventKey*>> maybeRestoreProcessingKeyEvent;
|
||||||
|
if (!mProcessingKeyEvent && !mPostingKeyEvents.IsEmpty()) {
|
||||||
|
GdkEventKey* keyEvent = mPostingKeyEvents.GetFirstEvent();
|
||||||
|
if (keyEvent && keyEvent->type == GDK_KEY_PRESS &&
|
||||||
|
KeymapWrapper::ComputeDOMKeyNameIndex(keyEvent) ==
|
||||||
|
KEY_NAME_INDEX_USE_STRING) {
|
||||||
|
maybeRestoreProcessingKeyEvent.emplace(mProcessingKeyEvent);
|
||||||
|
mProcessingKeyEvent = mPostingKeyEvents.GetFirstEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_LOG(gIMELog, LogLevel::Info,
|
MOZ_LOG(gIMELog, LogLevel::Info,
|
||||||
("0x%p OnCommitCompositionNative(aContext=0x%p), "
|
("0x%p OnCommitCompositionNative(aContext=0x%p), "
|
||||||
"current context=0x%p, active context=0x%p, commitString=\"%s\", "
|
"current context=0x%p, active context=0x%p, commitString=\"%s\", "
|
||||||
|
|
|
@ -267,6 +267,22 @@ class IMContextWrapper final : public TextEventDispatcherListener {
|
||||||
mEvents.RemoveElementAt(index);
|
mEvents.RemoveElementAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return corresponding GDK_KEY_PRESS event for aEvent. aEvent must be a
|
||||||
|
* GDK_KEY_RELEASE event.
|
||||||
|
*/
|
||||||
|
const GdkEventKey* GetCorrespondingKeyPressEvent(
|
||||||
|
const GdkEventKey* aEvent) const {
|
||||||
|
MOZ_ASSERT(aEvent->type == GDK_KEY_RELEASE);
|
||||||
|
for (const GUniquePtr<GdkEventKey>& pendingKeyEvent : mEvents) {
|
||||||
|
if (pendingKeyEvent->type == GDK_KEY_PRESS &&
|
||||||
|
aEvent->hardware_keycode == pendingKeyEvent->hardware_keycode) {
|
||||||
|
return pendingKeyEvent.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FirstEvent() returns oldest event in the queue.
|
* FirstEvent() returns oldest event in the queue.
|
||||||
*/
|
*/
|
||||||
|
|
Загрузка…
Ссылка в новой задаче