mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
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:
parent
0df404cf45
commit
0dfc1d00f9
@ -1059,6 +1059,17 @@ KeyHandlingState IMContextWrapper::OnKeyEvent(
|
||||
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(
|
||||
gIMELog, LogLevel::Debug,
|
||||
("0x%p OnKeyEvent(), succeeded, filterThisEvent=%s "
|
||||
@ -1615,6 +1626,21 @@ void IMContextWrapper::OnStartCompositionCallback(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,
|
||||
("0x%p OnStartCompositionNative(aContext=0x%p), "
|
||||
"current context=0x%p, mComposingContext=0x%p",
|
||||
@ -1702,6 +1728,21 @@ void IMContextWrapper::OnChangeCompositionCallback(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,
|
||||
("0x%p OnChangeCompositionNative(aContext=0x%p), "
|
||||
"mComposingContext=0x%p",
|
||||
@ -1833,6 +1874,21 @@ void IMContextWrapper::OnCommitCompositionNative(GtkIMContext* aContext,
|
||||
const gchar* commitString = aUTF8Char ? aUTF8Char : &emptyStr;
|
||||
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,
|
||||
("0x%p OnCommitCompositionNative(aContext=0x%p), "
|
||||
"current context=0x%p, active context=0x%p, commitString=\"%s\", "
|
||||
|
@ -267,6 +267,22 @@ class IMContextWrapper final : public TextEventDispatcherListener {
|
||||
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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user