From ef41c4154d677d98ea7c66755a7d658e39cb3fdd Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 2 Jun 2010 11:14:11 +0900 Subject: [PATCH] Bug 466487 ATOK (Japanese IME) fails to eat key message r=jimm --- widget/src/windows/nsAppShell.cpp | 6 ++- widget/src/windows/nsIMM32Handler.cpp | 76 ++++++++++++++++++++++++++- widget/src/windows/nsIMM32Handler.h | 20 +++++-- 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/widget/src/windows/nsAppShell.cpp b/widget/src/windows/nsAppShell.cpp index 0393c62cf4c8..d6cb25ed196d 100644 --- a/widget/src/windows/nsAppShell.cpp +++ b/widget/src/windows/nsAppShell.cpp @@ -42,6 +42,7 @@ #include "nsThreadUtils.h" #include "WinTaskbar.h" #include "nsString.h" +#include "nsIMM32Handler.h" // For skidmark code #include @@ -81,7 +82,7 @@ static BOOL PeekKeyAndIMEMessage(LPMSG msg, HWND hwnd) MSG msg1, msg2, *lpMsg; BOOL b1, b2; b1 = ::PeekMessageW(&msg1, NULL, WM_KEYFIRST, WM_IME_KEYLAST, PM_NOREMOVE); - b2 = ::PeekMessageW(&msg2, NULL, WM_IME_SETCONTEXT, WM_IME_KEYUP, PM_NOREMOVE); + b2 = ::PeekMessageW(&msg2, NULL, NS_WM_IMEFIRST, NS_WM_IMELAST, PM_NOREMOVE); if (b1 || b2) { if (b1 && b2) { if (msg1.time < msg2.time) @@ -92,6 +93,9 @@ static BOOL PeekKeyAndIMEMessage(LPMSG msg, HWND hwnd) lpMsg = &msg1; else lpMsg = &msg2; + if (!nsIMM32Handler::CanOptimizeKeyAndIMEMessages(lpMsg)) { + return false; + } return ::PeekMessageW(msg, hwnd, lpMsg->message, lpMsg->message, PM_REMOVE); } diff --git a/widget/src/windows/nsIMM32Handler.cpp b/widget/src/windows/nsIMM32Handler.cpp index 8bd5c38c3dbe..1ff78f3a9e8b 100644 --- a/widget/src/windows/nsIMM32Handler.cpp +++ b/widget/src/windows/nsIMM32Handler.cpp @@ -90,6 +90,8 @@ static UINT sWM_MSIME_MOUSE = 0; // mouse message for MSIME 98/2000 PRPackedBool nsIMM32Handler::sIsComposingOnPlugin = PR_FALSE; PRPackedBool nsIMM32Handler::sIsStatusChanged = PR_FALSE; +PRPackedBool nsIMM32Handler::sIsIME = PR_TRUE; +PRPackedBool nsIMM32Handler::sIsIMEOpening = PR_FALSE; #ifndef WINCE UINT nsIMM32Handler::sCodePage = 0; @@ -196,9 +198,10 @@ nsIMM32Handler::InitKeyboardLayout(HKL aKeyboardLayout) LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (PWSTR)&sCodePage, sizeof(sCodePage) / sizeof(WCHAR)); sIMEProperty = ::ImmGetProperty(aKeyboardLayout, IGP_PROPERTY); + sIsIME = ::ImmIsIME(aKeyboardLayout); PR_LOG(gIMM32Log, PR_LOG_ALWAYS, - ("IMM32: InitKeyboardLayout, aKeyboardLayout=%08x, sCodePage=%lu, sIMEProperty=%08x\n", - aKeyboardLayout, sCodePage, sIMEProperty)); + ("IMM32: InitKeyboardLayout, aKeyboardLayout=%08x, sCodePage=%lu, sIMEProperty=%08x sIsIME=%s\n", + aKeyboardLayout, sCodePage, sIMEProperty, sIsIME ? "TRUE" : "FALSE")); #endif } @@ -212,6 +215,21 @@ nsIMM32Handler::GetKeyboardCodePage() #endif } +/* static */ PRBool +nsIMM32Handler::CanOptimizeKeyAndIMEMessages(MSG *aNextKeyOrIMEMessage) +{ +#ifdef WINCE + return PR_TRUE; +#else + // If IME is opening right now, we shouldn't optimize the key and IME message + // order because ATOK (Japanese IME of third party) has some problem with the + // optimization. When it finishes opening completely, it eats all key + // messages in the message queue. And it causes starting composition. So, + // we shouldn't eat the key messages before ATOK. + return !sIsIMEOpening; +#endif +} + // used for checking the lParam of WM_IME_COMPOSITION #define IS_COMPOSING_LPARAM(lParam) \ @@ -273,6 +291,21 @@ nsIMM32Handler::ProcessMessage(nsWindow* aWindow, UINT msg, // if the new window handle is not focused, probably, we should not start // the composition, however, such case should not be, it's just bad scenario. + if (sIsIMEOpening) { + switch (msg) { + case WM_INPUTLANGCHANGE: + case WM_IME_STARTCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_CHAR: + case WM_IME_SELECT: + case WM_IME_SETCONTEXT: + // For safety, we should reset sIsIMEOpening when we receive unexpected + // message. + sIsIMEOpening = PR_FALSE; + } + } + if (aWindow->PluginHasFocus()) { return ProcessMessageForPlugin(aWindow, msg, wParam, lParam, aRetValue, aEatMessage); @@ -337,6 +370,8 @@ nsIMM32Handler::ProcessMessage(nsWindow* aWindow, UINT msg, case WM_IME_SETCONTEXT: aEatMessage = OnIMESetContext(aWindow, wParam, lParam); return PR_TRUE; + case WM_KEYDOWN: + return OnKeyDownEvent(aWindow, wParam, lParam, aEatMessage); default: return PR_FALSE; }; @@ -365,6 +400,20 @@ nsIMM32Handler::ProcessMessageForPlugin(nsWindow* aWindow, UINT msg, case WM_IME_ENDCOMPOSITION: sIsComposingOnPlugin = PR_FALSE; return PR_FALSE; + case WM_IME_NOTIFY: + if (wParam == IMN_SETOPENSTATUS) { + // finished being opening + sIsIMEOpening = PR_FALSE; + } + return PR_FALSE; + case WM_KEYDOWN: + if (wParam == VK_PROCESSKEY) { + // If we receive when IME isn't open, it means IME is opening right now. + nsIMEContext IMEContext(aWindow->GetWindowHandle()); + sIsIMEOpening = IMEContext.IsValid() && + ::ImmGetOpenStatus(IMEContext.get()); + } + return PR_FALSE; } return PR_FALSE; } @@ -543,6 +592,7 @@ nsIMM32Handler::OnIMENotify(nsWindow* aWindow, aWindow->GetWindowHandle())); break; case IMN_SETOPENSTATUS: + sIsIMEOpening = PR_FALSE; PR_LOG(gIMM32Log, PR_LOG_ALWAYS, ("IMM32: OnIMENotify, hWnd=%08x, IMN_SETOPENSTATUS\n", aWindow->GetWindowHandle())); @@ -1675,3 +1725,25 @@ nsIMM32Handler::OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction) } #endif // ENABLE_IME_MOUSE_HANDLING + +/* static */ PRBool +nsIMM32Handler::OnKeyDownEvent(nsWindow* aWindow, WPARAM wParam, LPARAM lParam, + PRBool &aEatMessage) +{ + PR_LOG(gIMM32Log, PR_LOG_ALWAYS, + ("IMM32: OnKeyDownEvent, hWnd=%08x, wParam=%08x, lParam=%08x\n", + aWindow->GetWindowHandle(), wParam, lParam)); + aEatMessage = PR_FALSE; + switch (wParam) { + case VK_PROCESSKEY: + // If we receive when IME isn't open, it means IME is opening right now. + if (sIsIME) { + nsIMEContext IMEContext(aWindow->GetWindowHandle()); + sIsIMEOpening = + IMEContext.IsValid() && !::ImmGetOpenStatus(IMEContext.get()); + } + return PR_FALSE; + default: + return PR_FALSE; + } +} diff --git a/widget/src/windows/nsIMM32Handler.h b/widget/src/windows/nsIMM32Handler.h index bfd4bd8b3a61..74a2607fcaa0 100644 --- a/widget/src/windows/nsIMM32Handler.h +++ b/widget/src/windows/nsIMM32Handler.h @@ -61,6 +61,9 @@ struct nsIntRect; #define ENABLE_IME_MOUSE_HANDLING 1 #endif // WINCE +#define NS_WM_IMEFIRST WM_IME_SETCONTEXT +#define NS_WM_IMELAST WM_IME_KEYUP + class nsIMEContext { public: @@ -123,6 +126,8 @@ public: static void NotifyEndStatusChange() { sIsStatusChanged = PR_FALSE; } + static PRBool CanOptimizeKeyAndIMEMessages(MSG *aNextKeyOrIMEMessage); + protected: static void EnsureHandlerInstance(); @@ -138,6 +143,14 @@ protected: nsIMM32Handler(); ~nsIMM32Handler(); + // The result of following On*Event methods means "The message was processed, + // don't process the message in the caller (nsWindow)". +#ifdef ENABLE_IME_MOUSE_HANDLING + PRBool OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction); +#endif // ENABLE_IME_MOUSE_HANDLING + static PRBool OnKeyDownEvent(nsWindow* aWindow, WPARAM wParam, LPARAM lParam, + PRBool &aEatMessage); + // The result of On* methods mean "eat this message" when it's TRUE. PRBool OnIMEStartComposition(nsWindow* aWindow); PRBool OnIMEComposition(nsWindow* aWindow, WPARAM wParam, LPARAM lParam); @@ -229,16 +242,13 @@ protected: static PRPackedBool sIsComposingOnPlugin; static PRPackedBool sIsStatusChanged; + static PRPackedBool sIsIME; + static PRPackedBool sIsIMEOpening; #ifndef WINCE static UINT sCodePage; static DWORD sIMEProperty; #endif // #ifndef WINCE - -#ifdef ENABLE_IME_MOUSE_HANDLING - PRBool OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction); -#endif // ENABLE_IME_MOUSE_HANDLING - }; #endif // nsIMM32Handler_h__