Bug 1300003 part.5 Remove odd WM_CHAR messages which are caused by ATOK or WXG (both of them are Japanese IME) r?m_kato
NativeKey removes odd WM_CHAR messages which are caused by ATOK or WXG if the user tries to do "Kakutei-Undo" (meaning "undo the last commit") after dispatching eKeyDown event.
However, NativeKey should remove them from the queue first because there are some problems:
* If focus is moved during dispatching an eKeyDown event, we'll fail to remove the messages from the queue.
* If dispatching eKeyDown advance native event loop due to entering to a modal loop or dosing synchronous XHR, the message pattern is broken before removing the odd messages from the queue.
After removing the odd char messages, NativeKey should store them with mRemovedOddCharMsgs because NativeKey needs to dispatch them to focused windowless plugin.
Note that this patch also fixes a bug of the loop to remove the odd WM_CHAR messages. Old code removes only one WM_CHAR messages, but we need to remove all WM_CHAR messages before WM_KEYUP. This must be a regression.
MozReview-Commit-ID: I60bcIx2SFS
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -1104,16 +1104,18 @@ NativeKey::NativeKey(nsWindowBase* aWidg
char16_t ch = static_cast<char16_t>(mFollowingCharMsgs[i].wParam);
// Skip control characters.
if (IsControlChar(ch)) {
continue;
}
mCommittedCharsAndModifiers.Append(ch, mModKeyState.GetModifiers());
}
}
+ // Remove odd char messages if there are.
+ RemoveFollowingOddCharMessages();
}
}
NativeKey::~NativeKey()
{
if (mIsOverridingKeyboardLayout) {
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
keyboardLayout->RestoreLayout();
@@ -1273,16 +1275,57 @@ NativeKey::IsIMEDoingKakuteiUndo() const
startCompositionMsg.lParam == 0x0 &&
compositionMsg.wParam == 0x0 &&
compositionMsg.lParam == 0x1BF &&
charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
startCompositionMsg.time <= compositionMsg.time &&
compositionMsg.time <= charMsg.time;
}
+void
+NativeKey::RemoveFollowingOddCharMessages()
+{
+ MOZ_ASSERT(IsKeyDownMessage());
+
+ // If the keydown message is synthesized for automated tests, there is
+ // nothing to do here.
+ if (mFakeCharMsgs) {
+ return;
+ }
+
+ // If there are some following char messages before another key message,
+ // there is nothing to do here.
+ if (!mFollowingCharMsgs.IsEmpty()) {
+ return;
+ }
+
+ // If the handling key isn't Backspace, there is nothing to do here.
+ if (mOriginalVirtualKeyCode != VK_BACK) {
+ return;
+ }
+
+ // If we don't see the odd message pattern, there is nothing to do here.
+ if (!IsIMEDoingKakuteiUndo()) {
+ return;
+ }
+
+ // Otherwise, we need to remove odd WM_CHAR messages for ATOK or WXG (both
+ // of them are Japanese IME).
+ MSG msg;
+ while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
+ PM_REMOVE | PM_NOYIELD)) {
+ if (msg.message != WM_CHAR) {
+ MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
+ "Unexpected message was removed");
+ continue;
+ }
+ mRemovedOddCharMsgs.AppendElement(msg);
+ }
+}
+
UINT
NativeKey::GetScanCodeWithExtendedFlag() const
{
// MapVirtualKeyEx() has been improved for supporting extended keys since
// Vista. When we call it for mapping a scancode of an extended key and
// a virtual keycode, we need to add 0xE000 to the scancode.
// On Win XP and Win Server 2003, this doesn't support. On them, we have
// no way to get virtual keycodes from scancode of extended keys.
@@ -2341,44 +2384,34 @@ NativeKey::GetFollowingCharMessage(MSG&
// TODO: Rename this method later.
bool
NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
{
MOZ_ASSERT(IsKeyDownMessage());
MOZ_ASSERT(!IsKeyMessageOnPlugin());
- bool anyCharMessagesRemoved = false;
for (size_t i = 0; i < mFollowingCharMsgs.Length(); ++i) {
- anyCharMessagesRemoved = true;
MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
"NativeKey tries to dispatch a plugin event on destroyed widget");
mWidget->DispatchPluginEvent(mFollowingCharMsgs[i]);
if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
return true;
}
}
- if (!mFakeCharMsgs && !anyCharMessagesRemoved &&
- mDOMKeyCode == NS_VK_BACK && IsIMEDoingKakuteiUndo()) {
- // This is for a hack for ATOK and WXG. So, PeekMessage() must scceed!
- MSG msg;
- while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
- PM_REMOVE | PM_NOYIELD)) {
- if (msg.message != WM_CHAR) {
- MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
- "Unexpected message was removed");
- continue;
- }
- MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
- "NativeKey tries to dispatch a plugin event on destroyed widget");
- mWidget->DispatchPluginEvent(msg);
- return mWidget->Destroyed();
+ // Dispatch odd char messages which are caused by ATOK or WXG (both of them
+ // are Japanese IME) and removed by RemoveFollowingOddCharMessages().
+ for (size_t i = 0; i < mRemovedOddCharMsgs.Length(); ++i) {
+ MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
+ "NativeKey tries to dispatch a plugin event on destroyed widget");
+ mWidget->DispatchPluginEvent(mRemovedOddCharMsgs[i]);
+ if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
+ return true;
}
- MOZ_CRASH("NativeKey failed to get WM_CHAR for ATOK or WXG");
}
return false;
}
void
NativeKey::ComputeInputtingStringWithKeyboardLayout()
{
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -262,16 +262,20 @@ private:
RefPtr<nsWindowBase> mWidget;
RefPtr<TextEventDispatcher> mDispatcher;
HKL mKeyboardLayout;
MSG mMsg;
// mFollowingCharMsgs stores WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or
// WM_SYSDEADCHAR message which follows WM_KEYDOWN.
// Note that the stored messaged are already removed from the queue.
nsTArray<MSG> mFollowingCharMsgs;
+ // mRemovedOddCharMsgs stores WM_CHAR messages which are caused by ATOK or
+ // WXG (they are Japanese IME) when the user tries to do "Kakutei-undo"
+ // (it means "undo the last commit").
+ nsTArray<MSG> mRemovedOddCharMsgs;
// If dispatching eKeyDown or eKeyPress event causes focus change,
// the instance shouldn't handle remaning char messages. For checking it,
// this should store first focused window.
HWND mFocusedWndBeforeDispatch;
uint32_t mDOMKeyCode;
KeyNameIndex mKeyNameIndex;
CodeNameIndex mCodeNameIndex;
@@ -372,16 +376,22 @@ private:
}
UINT GetScanCodeWithExtendedFlag() const;
// The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*.
uint32_t GetKeyLocation() const;
/**
+ * RemoveFollowingOddCharMessages() removes odd WM_CHAR messages from the
+ * queue when IsIMEDoingKakuteiUndo() returns true.
+ */
+ void RemoveFollowingOddCharMessages();
+
+ /**
* "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
* strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this
* returns true, the caller needs to be careful for processing the messages.
*/
bool IsIMEDoingKakuteiUndo() const;
bool IsKeyDownMessage() const
{