Index: base/message_pump_win.cc |
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc |
index 2b2a10e07534afcf7c7dd8de14567bd4c794d5cd..367e9e4dae102f3e5e75d352282195ead4c08c1b 100644 |
--- a/base/message_pump_win.cc |
+++ b/base/message_pump_win.cc |
@@ -4,14 +4,92 @@ |
#include "base/message_pump_win.h" |
+#include <imm.h> |
#include <math.h> |
+#include <msctf.h> |
+#include <Windows.h> |
#include "base/debug/trace_event.h" |
#include "base/message_loop.h" |
#include "base/metrics/histogram.h" |
#include "base/process_util.h" |
+#include "base/win/metro.h" |
+#include "base/win/scoped_comptr.h" |
#include "base/win/wrapped_window_proc.h" |
+namespace base { |
+ |
+static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; |
+ |
+// Message sent to get an additional time slice for pumping (processing) another |
+// task (a series of such messages creates a continuous task pump). |
+static const int kMsgHaveWork = WM_USER + 1; |
+ |
+class TextServicesBridge { |
+ public: |
+ TfClientId client_id; |
+ bool is_initialized; |
+ base::win::ScopedComPtr<ITfThreadMgr> thread_mgr; |
+ base::win::ScopedComPtr<ITfMessagePump> message_pump; |
+ base::win::ScopedComPtr<ITfKeystrokeMgr> keystroke_mgr; |
+ TextServicesBridge() |
+ : client_id(TF_CLIENTID_NULL), is_initialized(true) { |
+ is_initialized &= SUCCEEDED(thread_mgr.CreateInstance(CLSID_TF_ThreadMgr)); |
+ if (!thread_mgr) |
+ return; |
+ |
+ is_initialized &= SUCCEEDED(message_pump.QueryFrom(thread_mgr)); |
+ is_initialized &= SUCCEEDED(keystroke_mgr.QueryFrom(thread_mgr)); |
+ // When activate succeeded, |client_id| is set valid value. |
+ is_initialized &= SUCCEEDED(thread_mgr->Activate(&client_id)); |
+ } |
+ ~TextServicesBridge() { |
+ if (thread_mgr && client_id != TF_CLIENTID_NULL) |
+ thread_mgr->Deactivate(); |
+ } |
+ |
+ bool ForwardKeyMessageForTSF(const MSG& msg) { |
+ if (!is_initialized) |
+ return false; |
+ |
+ if(msg.message == WM_KEYDOWN) { |
+ BOOL eaten = FALSE; |
+ HRESULT hr = keystroke_mgr->TestKeyDown(msg.wParam, msg.lParam, &eaten); |
+ if (FAILED(hr) && !eaten) |
+ return false; |
+ eaten = FALSE; |
+ hr = keystroke_mgr->KeyDown(msg.wParam, msg.lParam, &eaten); |
+ return (SUCCEEDED(hr) && eaten); |
+ } |
+ |
+ if(msg.message == WM_KEYUP) { |
+ BOOL eaten = FALSE; |
+ HRESULT hr = keystroke_mgr->TestKeyUp(msg.wParam, msg.lParam, &eaten); |
+ if (FAILED(hr) && !eaten) |
+ return false; |
+ eaten = FALSE; |
+ hr = keystroke_mgr->KeyUp(msg.wParam, msg.lParam, &eaten); |
+ return (SUCCEEDED(hr) && eaten); |
+ } |
+ |
+ return false; |
+ } |
+ |
+ bool PeekMessageForTSF(MSG* msg, HWND hwnd, UINT wMsgFilterMin, |
+ UINT wMsgFilterMax, UINT wRemoveMsg) { |
+ if (!is_initialized) |
+ // FallBack. |
+ return !!::PeekMessage(msg, hwnd, wMsgFilterMin, wMsgFilterMax, |
+ wRemoveMsg); |
+ |
+ BOOL result = FALSE; |
+ if(FAILED(message_pump->PeekMessage(msg, hwnd, wMsgFilterMin, wMsgFilterMax, |
+ wRemoveMsg, &result))) |
+ result = FALSE; |
+ return !!result; |
+ } |
+}; |
+ |
namespace { |
enum MessageLoopProblems { |
@@ -23,14 +101,6 @@ enum MessageLoopProblems { |
} // namespace |
-namespace base { |
- |
-static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; |
- |
-// Message sent to get an additional time slice for pumping (processing) another |
-// task (a series of such messages creates a continuous task pump). |
-static const int kMsgHaveWork = WM_USER + 1; |
- |
//----------------------------------------------------------------------------- |
// MessagePumpWin public: |
@@ -97,9 +167,14 @@ int MessagePumpWin::GetCurrentDelay() const { |
MessagePumpForUI::MessagePumpForUI() : instance_(NULL) { |
InitMessageWnd(); |
+ |
+ if (base::win::IsTsfAwareRequired()) |
+ text_services_bridge_.reset(new TextServicesBridge); |
} |
MessagePumpForUI::~MessagePumpForUI() { |
+ if (base::win::IsTsfAwareRequired()) |
+ text_services_bridge_.reset(NULL); |
DestroyWindow(message_hwnd_); |
UnregisterClass(kWndClass, instance_); |
} |
@@ -182,7 +257,7 @@ void MessagePumpForUI::PumpOutPendingPaintMessages() { |
int peek_count; |
for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { |
MSG msg; |
- if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) |
+ if (!ProcessPeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) |
break; |
ProcessMessageHelper(msg); |
if (state_->should_quit) // Handle WM_QUIT. |
@@ -304,7 +379,8 @@ void MessagePumpForUI::WaitForWork() { |
MSG msg = {0}; |
DWORD queue_status = GetQueueStatus(QS_MOUSE); |
if (HIWORD(queue_status) & QS_MOUSE && |
- !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { |
+ !ProcessPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, |
+ PM_NOREMOVE)) { |
WaitMessage(); |
} |
return; |
@@ -361,7 +437,7 @@ bool MessagePumpForUI::ProcessNextWindowsMessage() { |
sent_messages_in_queue = true; |
MSG msg; |
- if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) |
+ if (ProcessPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) |
return ProcessMessageHelper(msg); |
return sent_messages_in_queue; |
@@ -387,12 +463,20 @@ bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { |
WillProcessMessage(msg); |
- if (state_->dispatcher) { |
- if (!state_->dispatcher->Dispatch(msg)) |
- state_->should_quit = true; |
- } else { |
- TranslateMessage(&msg); |
- DispatchMessage(&msg); |
+ bool is_key_dispatched_by_tsf = false; |
+ if (base::win::IsTsfAwareRequired()) { |
+ is_key_dispatched_by_tsf = |
+ text_services_bridge_->ForwardKeyMessageForTSF(msg); |
+ } |
+ |
+ if (!is_key_dispatched_by_tsf) { |
+ if (state_->dispatcher) { |
+ if (!state_->dispatcher->Dispatch(msg)) |
+ state_->should_quit = true; |
+ } else { |
+ TranslateMessage(&msg); |
+ DispatchMessage(&msg); |
+ } |
} |
DidProcessMessage(msg); |
@@ -416,10 +500,11 @@ bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
// This is to ensure that these messages are peeked out by the OS modal loop. |
if (MessageLoop::current()->os_modal_loop()) { |
// We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. |
- have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
- PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
+ have_message = |
+ ProcessPeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || |
Yohei Yukawa
2012/08/16 02:54:46
nit: indent.
yoichio
2012/08/16 06:14:13
Done.
|
+ ProcessPeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); |
} else { |
- have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); |
+ have_message = ProcessPeekMessage(&msg, NULL, 0, 0, PM_REMOVE); |
} |
DCHECK(!have_message || kMsgHaveWork != msg.message || |
@@ -441,6 +526,16 @@ bool MessagePumpForUI::ProcessPumpReplacementMessage() { |
return ProcessMessageHelper(msg); |
} |
+bool MessagePumpForUI::ProcessPeekMessage( |
+ MSG* pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg) |
+{ |
+ if (base::win::IsTsfAwareRequired()) |
+ return text_services_bridge_->PeekMessageForTSF( |
+ pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); |
+ |
+ return !!::PeekMessage(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); |
+} |
+ |
//----------------------------------------------------------------------------- |
// MessagePumpForIO public: |