root/win8/metro_driver/ime/ime_popup_monitor.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ImeEventCallback
  2. AddImePopupObserver
  3. RemoveImePopupObserver

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "win8/metro_driver/ime/ime_popup_monitor.h"

#include <windows.h>

#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "win8/metro_driver/ime/ime_popup_observer.h"

namespace metro_driver {
namespace {

ImePopupObserver* g_observer_ = NULL;
HWINEVENTHOOK g_hook_handle_ = NULL;

void CALLBACK ImeEventCallback(HWINEVENTHOOK win_event_hook_handle,
                               DWORD event,
                               HWND window_handle,
                               LONG object_id,
                               LONG child_id,
                               DWORD event_thread,
                               DWORD event_time) {
  // This function is registered to SetWinEventHook to be called back on the UI
  // thread.
  DCHECK(base::MessageLoopForUI::IsCurrent());

  if (!g_observer_)
    return;
  switch (event) {
    case EVENT_OBJECT_IME_SHOW:
      g_observer_->OnImePopupChanged(ImePopupObserver::kPopupShown);
      return;
    case EVENT_OBJECT_IME_HIDE:
      g_observer_->OnImePopupChanged(ImePopupObserver::kPopupHidden);
      return;
    case EVENT_OBJECT_IME_CHANGE:
      g_observer_->OnImePopupChanged(ImePopupObserver::kPopupUpdated);
      return;
  }
}

}  // namespace

void AddImePopupObserver(ImePopupObserver* observer) {
  CHECK(g_observer_ == NULL)
      << "Currently only one observer is supported at the same time.";
  g_observer_ = observer;

  // IMEs running under immersive mode are supposed to generate WinEvent
  // whenever their popup UI such as candidate window is shown, updated, and
  // hidden to support accessibility applications.
  // http://msdn.microsoft.com/en-us/library/windows/apps/hh967425.aspx#accessibility
  // Note that there is another mechanism in TSF, called ITfUIElementSink, to
  // subscribe when the visibility of an IME's UI element is changed. However,
  // MS-IME running under immersive mode does not fully support this API.
  // Thus, WinEvent is more reliable for this purpose.
  g_hook_handle_ = SetWinEventHook(
      EVENT_OBJECT_IME_SHOW,
      EVENT_OBJECT_IME_CHANGE,
      NULL,
      ImeEventCallback,
      GetCurrentProcessId(),  // monitor the metro_driver process only
      0,   // hook all threads because MS-IME emits WinEvent in a worker thread
      WINEVENT_OUTOFCONTEXT);  // allows us to receive message in the UI thread
  LOG_IF(ERROR, !g_hook_handle_) << "SetWinEventHook failed.";
}

void RemoveImePopupObserver(ImePopupObserver* observer) {
  if (g_observer_ != observer)
    return;
  g_observer_ = NULL;
  if (!g_hook_handle_)
    return;
  const bool unhook_succeeded = !!UnhookWinEvent(g_hook_handle_);
  LOG_IF(ERROR, !unhook_succeeded) << "UnhookWinEvent failed.";
  g_hook_handle_ = NULL;
}

}  // namespace metro_driver

/* [<][>][^][v][top][bottom][index][help] */