Home | History | Annotate | Download | only in metro_driver
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "win8/metro_driver/stdafx.h"
      6 #include "win8/metro_driver/chrome_app_view_ash.h"
      7 
      8 #include <corewindow.h>
      9 #include <shellapi.h>
     10 #include <windows.foundation.h>
     11 
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/files/file_path.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/path_service.h"
     17 #include "base/threading/thread.h"
     18 #include "base/win/metro.h"
     19 #include "base/win/win_util.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "ipc/ipc_channel.h"
     22 #include "ipc/ipc_channel_proxy.h"
     23 #include "ipc/ipc_sender.h"
     24 #include "ui/events/gestures/gesture_sequence.h"
     25 #include "ui/metro_viewer/metro_viewer_messages.h"
     26 #include "win8/metro_driver/file_picker_ash.h"
     27 #include "win8/metro_driver/ime/ime_popup_monitor.h"
     28 #include "win8/metro_driver/ime/input_source.h"
     29 #include "win8/metro_driver/ime/text_service.h"
     30 #include "win8/metro_driver/metro_driver.h"
     31 #include "win8/metro_driver/winrt_utils.h"
     32 #include "win8/viewer/metro_viewer_constants.h"
     33 
     34 typedef winfoundtn::ITypedEventHandler<
     35     winapp::Core::CoreApplicationView*,
     36     winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
     37 
     38 typedef winfoundtn::ITypedEventHandler<
     39     winui::Core::CoreWindow*,
     40     winui::Core::PointerEventArgs*> PointerEventHandler;
     41 
     42 typedef winfoundtn::ITypedEventHandler<
     43     winui::Core::CoreWindow*,
     44     winui::Core::KeyEventArgs*> KeyEventHandler;
     45 
     46 typedef winfoundtn::ITypedEventHandler<
     47     winui::Core::CoreDispatcher*,
     48     winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler;
     49 
     50 typedef winfoundtn::ITypedEventHandler<
     51     winui::Core::CoreWindow*,
     52     winui::Core::CharacterReceivedEventArgs*> CharEventHandler;
     53 
     54 typedef winfoundtn::ITypedEventHandler<
     55     winui::Core::CoreWindow*,
     56     winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler;
     57 
     58 typedef winfoundtn::ITypedEventHandler<
     59     winui::Core::CoreWindow*,
     60     winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
     61 
     62 typedef winfoundtn::ITypedEventHandler<
     63     winui::Input::EdgeGesture*,
     64     winui::Input::EdgeGestureEventArgs*> EdgeEventHandler;
     65 
     66 // This function is exported by chrome.exe.
     67 typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info);
     68 
     69 // Global information used across the metro driver.
     70 struct Globals {
     71   winapp::Activation::ApplicationExecutionState previous_state;
     72   winapp::Core::ICoreApplicationExit* app_exit;
     73   BreakpadExceptionHandler breakpad_exception_handler;
     74 } globals;
     75 
     76 namespace {
     77 
     78 enum KeyModifier {
     79   NONE,
     80   SHIFT = 1,
     81   CONTROL = 2,
     82   ALT = 4
     83 };
     84 
     85 // Helper function to send keystrokes via the SendInput function.
     86 // mnemonic_char: The keystroke to be sent.
     87 // modifiers: Combination with Alt, Ctrl, Shift, etc.
     88 void SendMnemonic(
     89     WORD mnemonic_char, KeyModifier modifiers) {
     90   INPUT keys[4] = {0};  // Keyboard events
     91   int key_count = 0;  // Number of generated events
     92 
     93   if (modifiers & SHIFT) {
     94     keys[key_count].type = INPUT_KEYBOARD;
     95     keys[key_count].ki.wVk = VK_SHIFT;
     96     keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
     97     key_count++;
     98   }
     99 
    100   if (modifiers & CONTROL) {
    101     keys[key_count].type = INPUT_KEYBOARD;
    102     keys[key_count].ki.wVk = VK_CONTROL;
    103     keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
    104     key_count++;
    105   }
    106 
    107   if (modifiers & ALT) {
    108     keys[key_count].type = INPUT_KEYBOARD;
    109     keys[key_count].ki.wVk = VK_MENU;
    110     keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
    111     key_count++;
    112   }
    113 
    114   keys[key_count].type = INPUT_KEYBOARD;
    115   keys[key_count].ki.wVk = mnemonic_char;
    116   keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
    117   key_count++;
    118 
    119   bool should_sleep = key_count > 1;
    120 
    121   // Send key downs.
    122   for (int i = 0; i < key_count; i++) {
    123     SendInput(1, &keys[ i ], sizeof(keys[0]));
    124     keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
    125     if (should_sleep)
    126       Sleep(10);
    127   }
    128 
    129   // Now send key ups in reverse order.
    130   for (int i = key_count; i; i--) {
    131     SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
    132     if (should_sleep)
    133       Sleep(10);
    134   }
    135 }
    136 
    137 // Helper function to Exit metro chrome cleanly. If we are in the foreground
    138 // then we try and exit by sending an Alt+F4 key combination to the core
    139 // window which ensures that the chrome application tile does not show up in
    140 // the running metro apps list on the top left corner.
    141 void MetroExit(HWND core_window) {
    142   if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) {
    143     DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
    144     SendMnemonic(VK_F4, ALT);
    145   } else {
    146     globals.app_exit->Exit();
    147   }
    148 }
    149 
    150 class ChromeChannelListener : public IPC::Listener {
    151  public:
    152   ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
    153       : ui_proxy_(ui_loop->message_loop_proxy()),
    154         app_view_(app_view) {}
    155 
    156   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    157     IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
    158       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop,
    159                           OnActivateDesktop)
    160       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit, OnMetroExit)
    161       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop,
    162                           OnOpenURLOnDesktop)
    163       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
    164       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen,
    165                           OnDisplayFileOpenDialog)
    166       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs,
    167                           OnDisplayFileSaveAsDialog)
    168       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder,
    169                           OnDisplayFolderPicker)
    170       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos)
    171       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition,
    172                           OnImeCancelComposition)
    173       IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated,
    174                           OnImeTextInputClientChanged)
    175       IPC_MESSAGE_UNHANDLED(__debugbreak())
    176     IPC_END_MESSAGE_MAP()
    177     return true;
    178   }
    179 
    180   virtual void OnChannelError() OVERRIDE {
    181     DVLOG(1) << "Channel error. Exiting.";
    182     MetroExit(app_view_->core_window_hwnd());
    183     // In early Windows 8 versions the code above sometimes fails so we call
    184     // it a second time with a NULL window which just calls Exit().
    185     ui_proxy_->PostDelayedTask(FROM_HERE,
    186         base::Bind(&MetroExit, HWND(NULL)),
    187         base::TimeDelta::FromMilliseconds(100));
    188   }
    189 
    190  private:
    191   void OnActivateDesktop(const base::FilePath& shortcut, bool ash_exit) {
    192     ui_proxy_->PostTask(FROM_HERE,
    193         base::Bind(&ChromeAppViewAsh::OnActivateDesktop,
    194         base::Unretained(app_view_),
    195         shortcut, ash_exit));
    196   }
    197 
    198   void OnMetroExit() {
    199     MetroExit(app_view_->core_window_hwnd());
    200   }
    201 
    202   void OnOpenURLOnDesktop(const base::FilePath& shortcut,
    203                           const string16& url) {
    204     ui_proxy_->PostTask(FROM_HERE,
    205         base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop,
    206         base::Unretained(app_view_),
    207         shortcut, url));
    208   }
    209 
    210   void OnSetCursor(int64 cursor) {
    211     ui_proxy_->PostTask(FROM_HERE,
    212                         base::Bind(&ChromeAppViewAsh::OnSetCursor,
    213                                    base::Unretained(app_view_),
    214                                    reinterpret_cast<HCURSOR>(cursor)));
    215   }
    216 
    217   void OnDisplayFileOpenDialog(const string16& title,
    218                                const string16& filter,
    219                                const base::FilePath& default_path,
    220                                bool allow_multiple_files) {
    221     ui_proxy_->PostTask(FROM_HERE,
    222                         base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog,
    223                                    base::Unretained(app_view_),
    224                                    title,
    225                                    filter,
    226                                    default_path,
    227                                    allow_multiple_files));
    228   }
    229 
    230   void OnDisplayFileSaveAsDialog(
    231     const MetroViewerHostMsg_SaveAsDialogParams& params) {
    232     ui_proxy_->PostTask(
    233         FROM_HERE,
    234         base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog,
    235                    base::Unretained(app_view_),
    236                    params));
    237   }
    238 
    239   void OnDisplayFolderPicker(const string16& title) {
    240     ui_proxy_->PostTask(
    241         FROM_HERE,
    242         base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker,
    243                    base::Unretained(app_view_),
    244                    title));
    245   }
    246 
    247   void OnSetCursorPos(int x, int y) {
    248     VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y;
    249     ui_proxy_->PostTask(
    250         FROM_HERE,
    251         base::Bind(&ChromeAppViewAsh::OnSetCursorPos,
    252                    base::Unretained(app_view_),
    253                    x, y));
    254   }
    255 
    256   void OnImeCancelComposition() {
    257     ui_proxy_->PostTask(
    258         FROM_HERE,
    259         base::Bind(&ChromeAppViewAsh::OnImeCancelComposition,
    260                    base::Unretained(app_view_)));
    261   }
    262 
    263   void OnImeTextInputClientChanged(
    264       const std::vector<int32>& input_scopes,
    265       const std::vector<metro_viewer::CharacterBounds>& character_bounds) {
    266     ui_proxy_->PostTask(
    267         FROM_HERE,
    268         base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient,
    269                    base::Unretained(app_view_),
    270                    input_scopes,
    271                    character_bounds));
    272   }
    273 
    274   scoped_refptr<base::MessageLoopProxy> ui_proxy_;
    275   ChromeAppViewAsh* app_view_;
    276 };
    277 
    278 bool WaitForChromeIPCConnection(const std::string& channel_name) {
    279   int ms_elapsed = 0;
    280   while (!IPC::Channel::IsNamedServerInitialized(channel_name) &&
    281          ms_elapsed < 10000) {
    282     ms_elapsed += 500;
    283     Sleep(500);
    284   }
    285   return IPC::Channel::IsNamedServerInitialized(channel_name);
    286 }
    287 
    288 // This class helps decoding the pointer properties of an event.
    289 class PointerInfoHandler {
    290  public:
    291   PointerInfoHandler()
    292       : x_(0),
    293         y_(0),
    294         wheel_delta_(0),
    295         update_kind_(winui::Input::PointerUpdateKind_Other),
    296         timestamp_(0),
    297         pointer_id_(0) {}
    298 
    299   HRESULT Init(winui::Core::IPointerEventArgs* args) {
    300     HRESULT hr = args->get_CurrentPoint(&pointer_point_);
    301     if (FAILED(hr))
    302       return hr;
    303 
    304     winfoundtn::Point point;
    305     hr = pointer_point_->get_Position(&point);
    306     if (FAILED(hr))
    307       return hr;
    308 
    309     mswr::ComPtr<winui::Input::IPointerPointProperties> properties;
    310     hr = pointer_point_->get_Properties(&properties);
    311     if (FAILED(hr))
    312       return hr;
    313 
    314     hr = properties->get_PointerUpdateKind(&update_kind_);
    315     if (FAILED(hr))
    316       return hr;
    317 
    318     hr = properties->get_MouseWheelDelta(&wheel_delta_);
    319     if (FAILED(hr))
    320       return hr;
    321     x_ = point.X;
    322     y_ = point.Y;
    323     pointer_point_->get_Timestamp(&timestamp_);
    324     pointer_point_->get_PointerId(&pointer_id_);
    325     // Map the OS touch event id to a range allowed by the gesture recognizer.
    326     if (IsTouch())
    327       pointer_id_ %= ui::GestureSequence::kMaxGesturePoints;
    328     return S_OK;
    329   }
    330 
    331   bool IsType(windevs::Input::PointerDeviceType type) const {
    332     mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device;
    333     CheckHR(pointer_point_->get_PointerDevice(&pointer_device));
    334     windevs::Input::PointerDeviceType device_type;
    335     CheckHR(pointer_device->get_PointerDeviceType(&device_type));
    336     return  (device_type == type);
    337   }
    338 
    339   bool IsMouse() const {
    340     return IsType(windevs::Input::PointerDeviceType_Mouse);
    341   }
    342 
    343   bool IsTouch() const {
    344     return IsType(windevs::Input::PointerDeviceType_Touch);
    345   }
    346 
    347   int32 wheel_delta() const {
    348     return wheel_delta_;
    349   }
    350 
    351   ui::EventFlags flags() {
    352     switch (update_kind_) {
    353       case winui::Input::PointerUpdateKind_LeftButtonPressed:
    354         return ui::EF_LEFT_MOUSE_BUTTON;
    355       case winui::Input::PointerUpdateKind_LeftButtonReleased:
    356         return ui::EF_LEFT_MOUSE_BUTTON;
    357       case winui::Input::PointerUpdateKind_RightButtonPressed:
    358         return ui::EF_RIGHT_MOUSE_BUTTON;
    359       case winui::Input::PointerUpdateKind_RightButtonReleased:
    360         return ui::EF_RIGHT_MOUSE_BUTTON;
    361       case winui::Input::PointerUpdateKind_MiddleButtonPressed:
    362         return ui::EF_MIDDLE_MOUSE_BUTTON;
    363       case winui::Input::PointerUpdateKind_MiddleButtonReleased:
    364         return ui::EF_MIDDLE_MOUSE_BUTTON;
    365       default:
    366         return ui::EF_NONE;
    367     };
    368   }
    369 
    370   int x() const { return x_; }
    371   int y() const { return y_; }
    372 
    373   uint32 pointer_id() const {
    374     return pointer_id_;
    375   }
    376 
    377   uint64 timestamp() const { return timestamp_; }
    378 
    379  private:
    380   int x_;
    381   int y_;
    382   int wheel_delta_;
    383   uint32 pointer_id_;
    384   winui::Input::PointerUpdateKind update_kind_;
    385   mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_;
    386   uint64 timestamp_;
    387 };
    388 
    389 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
    390   // We're entering a nested message loop, let's allow dispatching
    391   // tasks while we're in there.
    392   base::MessageLoop::current()->SetNestableTasksAllowed(true);
    393 
    394   // Enter main core message loop. There are several ways to exit it
    395   // Nicely:
    396   // 1 - User action like ALT-F4.
    397   // 2 - Calling ICoreApplicationExit::Exit().
    398   // 3-  Posting WM_CLOSE to the core window.
    399   HRESULT hr = dispatcher->ProcessEvents(
    400       winui::Core::CoreProcessEventsOption
    401           ::CoreProcessEventsOption_ProcessUntilQuit);
    402 
    403   // Wind down the thread's chrome message loop.
    404   base::MessageLoop::current()->Quit();
    405 }
    406 
    407 // Helper to return the state of the shift/control/alt keys.
    408 uint32 GetKeyboardEventFlags() {
    409   uint32 flags = 0;
    410   if (base::win::IsShiftPressed())
    411     flags |= ui::EF_SHIFT_DOWN;
    412   if (base::win::IsCtrlPressed())
    413     flags |= ui::EF_CONTROL_DOWN;
    414   if (base::win::IsAltPressed())
    415     flags |= ui::EF_ALT_DOWN;
    416   return flags;
    417 }
    418 
    419 bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters,
    420                                 winapp::Activation::IActivatedEventArgs* args) {
    421   if (args) {
    422     DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW();
    423     winapp::Activation::ActivationKind activation_kind;
    424     CheckHR(args->get_Kind(&activation_kind));
    425 
    426     DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind;
    427 
    428     if (activation_kind == winapp::Activation::ActivationKind_Launch) {
    429       mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args;
    430       if (args->QueryInterface(
    431               winapp::Activation::IID_ILaunchActivatedEventArgs,
    432               &launch_args) == S_OK) {
    433         DVLOG(1) << "Activate: ActivationKind_Launch";
    434         mswrw::HString launch_args_str;
    435         launch_args->get_Arguments(launch_args_str.GetAddressOf());
    436         string16 actual_launch_args(MakeStdWString(launch_args_str.Get()));
    437         if (actual_launch_args == win8::kMetroViewerConnectVerb) {
    438           DVLOG(1) << __FUNCTION__ << "Not launching chrome server";
    439           return true;
    440         }
    441       }
    442     }
    443   }
    444 
    445   DVLOG(1) << "Launching chrome server";
    446   base::FilePath chrome_exe_path;
    447 
    448   if (!PathService::Get(base::FILE_EXE, &chrome_exe_path))
    449     return false;
    450 
    451   string16 parameters = L"--silent-launch --viewer-connect ";
    452   if (additional_parameters)
    453     parameters += additional_parameters;
    454 
    455   SHELLEXECUTEINFO sei = { sizeof(sei) };
    456   sei.nShow = SW_SHOWNORMAL;
    457   sei.lpFile = chrome_exe_path.value().c_str();
    458   sei.lpDirectory = L"";
    459   sei.lpParameters = parameters.c_str();
    460   ::ShellExecuteEx(&sei);
    461   return true;
    462 }
    463 
    464 }  // namespace
    465 
    466 ChromeAppViewAsh::ChromeAppViewAsh()
    467     : mouse_down_flags_(ui::EF_NONE),
    468       ui_channel_(nullptr),
    469       core_window_hwnd_(NULL),
    470       ui_loop_(base::MessageLoop::TYPE_UI) {
    471   DVLOG(1) << __FUNCTION__;
    472   globals.previous_state =
    473       winapp::Activation::ApplicationExecutionState_NotRunning;
    474 }
    475 
    476 ChromeAppViewAsh::~ChromeAppViewAsh() {
    477   DVLOG(1) << __FUNCTION__;
    478 }
    479 
    480 IFACEMETHODIMP
    481 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) {
    482   view_ = view;
    483   DVLOG(1) << __FUNCTION__;
    484   HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
    485       this, &ChromeAppViewAsh::OnActivate).Get(),
    486       &activated_token_);
    487   CheckHR(hr);
    488   return hr;
    489 }
    490 
    491 IFACEMETHODIMP
    492 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) {
    493   window_ = window;
    494   DVLOG(1) << __FUNCTION__;
    495 
    496   // Retrieve the native window handle via the interop layer.
    497   mswr::ComPtr<ICoreWindowInterop> interop;
    498   HRESULT hr = window->QueryInterface(interop.GetAddressOf());
    499   CheckHR(hr);
    500   hr = interop->get_WindowHandle(&core_window_hwnd_);
    501   CheckHR(hr);
    502 
    503   text_service_ = metro_driver::CreateTextService(this, core_window_hwnd_);
    504 
    505   hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
    506       this, &ChromeAppViewAsh::OnSizeChanged).Get(),
    507       &sizechange_token_);
    508   CheckHR(hr);
    509 
    510   // Register for pointer and keyboard notifications. We forward
    511   // them to the browser process via IPC.
    512   hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>(
    513       this, &ChromeAppViewAsh::OnPointerMoved).Get(),
    514       &pointermoved_token_);
    515   CheckHR(hr);
    516 
    517   hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>(
    518       this, &ChromeAppViewAsh::OnPointerPressed).Get(),
    519       &pointerpressed_token_);
    520   CheckHR(hr);
    521 
    522   hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>(
    523       this, &ChromeAppViewAsh::OnPointerReleased).Get(),
    524       &pointerreleased_token_);
    525   CheckHR(hr);
    526 
    527   hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>(
    528       this, &ChromeAppViewAsh::OnKeyDown).Get(),
    529       &keydown_token_);
    530   CheckHR(hr);
    531 
    532   hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>(
    533       this, &ChromeAppViewAsh::OnKeyUp).Get(),
    534       &keyup_token_);
    535   CheckHR(hr);
    536 
    537   mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
    538   hr = window_->get_Dispatcher(&dispatcher);
    539   CheckHR(hr, "Get Dispatcher failed.");
    540 
    541   mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys;
    542   hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys),
    543                          reinterpret_cast<void**>(
    544                             accelerator_keys.GetAddressOf()));
    545   CheckHR(hr, "QI for ICoreAcceleratorKeys failed.");
    546   hr = accelerator_keys->add_AcceleratorKeyActivated(
    547       mswr::Callback<AcceleratorKeyEventHandler>(
    548           this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(),
    549       &accel_keydown_token_);
    550   CheckHR(hr);
    551 
    552   hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>(
    553       this, &ChromeAppViewAsh::OnWheel).Get(),
    554       &wheel_token_);
    555   CheckHR(hr);
    556 
    557   hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>(
    558       this, &ChromeAppViewAsh::OnCharacterReceived).Get(),
    559       &character_received_token_);
    560   CheckHR(hr);
    561 
    562   hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>(
    563       this, &ChromeAppViewAsh::OnWindowActivated).Get(),
    564       &window_activated_token_);
    565   CheckHR(hr);
    566 
    567   // Register for edge gesture notifications.
    568   mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics;
    569   hr = winrt_utils::CreateActivationFactory(
    570       RuntimeClass_Windows_UI_Input_EdgeGesture,
    571       edge_gesture_statics.GetAddressOf());
    572   CheckHR(hr);
    573 
    574   mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture;
    575   hr = edge_gesture_statics->GetForCurrentView(&edge_gesture);
    576   CheckHR(hr);
    577 
    578   hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>(
    579       this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(),
    580       &edgeevent_token_);
    581   CheckHR(hr);
    582 
    583   // By initializing the direct 3D swap chain with the corewindow
    584   // we can now directly blit to it from the browser process.
    585   direct3d_helper_.Initialize(window);
    586   DVLOG(1) << "Initialized Direct3D.";
    587   return S_OK;
    588 }
    589 
    590 IFACEMETHODIMP
    591 ChromeAppViewAsh::Load(HSTRING entryPoint) {
    592   DVLOG(1) << __FUNCTION__;
    593   return S_OK;
    594 }
    595 
    596 IFACEMETHODIMP
    597 ChromeAppViewAsh::Run() {
    598   DVLOG(1) << __FUNCTION__;
    599   mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
    600   HRESULT hr = window_->get_Dispatcher(&dispatcher);
    601   CheckHR(hr, "Dispatcher failed.");
    602 
    603   hr = window_->Activate();
    604   if (FAILED(hr)) {
    605     DLOG(WARNING) << "activation failed hr=" << hr;
    606     return hr;
    607   }
    608 
    609   // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
    610   base::Thread io_thread("metro_IO_thread");
    611   base::Thread::Options options;
    612   options.message_loop_type = base::MessageLoop::TYPE_IO;
    613   io_thread.StartWithOptions(options);
    614 
    615   // Start up Chrome and wait for the desired IPC server connection to exist.
    616   WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName);
    617 
    618   // In Aura mode we create an IPC channel to the browser, then ask it to
    619   // connect to us.
    620   ChromeChannelListener ui_channel_listener(&ui_loop_, this);
    621   IPC::ChannelProxy ui_channel(win8::kMetroViewerIPCChannelName,
    622                                IPC::Channel::MODE_NAMED_CLIENT,
    623                                &ui_channel_listener,
    624                                io_thread.message_loop_proxy());
    625   ui_channel_ = &ui_channel;
    626 
    627   // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
    628   // browser will use D3D from the browser process to present to our Window.
    629   ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface(
    630                     gfx::NativeViewId(core_window_hwnd_)));
    631   DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_;
    632 
    633   // Send an initial size message so that the Ash root window host gets sized
    634   // correctly.
    635   RECT rect = {0};
    636   ::GetWindowRect(core_window_hwnd_, &rect);
    637   ui_channel_->Send(
    638       new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left,
    639                                                rect.bottom - rect.top));
    640 
    641   input_source_ = metro_driver::InputSource::Create();
    642   if (input_source_) {
    643     input_source_->AddObserver(this);
    644     // Send an initial input source.
    645     OnInputSourceChanged();
    646   }
    647 
    648   // Start receiving IME popup window notifications.
    649   metro_driver::AddImePopupObserver(this);
    650 
    651   // And post the task that'll do the inner Metro message pumping to it.
    652   ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
    653   ui_loop_.Run();
    654 
    655   DVLOG(0) << "ProcessEvents done, hr=" << hr;
    656   return hr;
    657 }
    658 
    659 IFACEMETHODIMP
    660 ChromeAppViewAsh::Uninitialize() {
    661   DVLOG(1) << __FUNCTION__;
    662   metro_driver::RemoveImePopupObserver(this);
    663   input_source_.reset();
    664   text_service_.reset();
    665   window_ = nullptr;
    666   view_ = nullptr;
    667   core_window_hwnd_ = NULL;
    668   return S_OK;
    669 }
    670 
    671 // static
    672 HRESULT ChromeAppViewAsh::Unsnap() {
    673   mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
    674   HRESULT hr = winrt_utils::CreateActivationFactory(
    675       RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
    676       view_statics.GetAddressOf());
    677   CheckHR(hr);
    678 
    679   winui::ViewManagement::ApplicationViewState state =
    680       winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
    681   hr = view_statics->get_Value(&state);
    682   CheckHR(hr);
    683 
    684   if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
    685     boolean success = FALSE;
    686     hr = view_statics->TryUnsnap(&success);
    687 
    688     if (FAILED(hr) || !success) {
    689       LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
    690       if (SUCCEEDED(hr))
    691         hr = E_UNEXPECTED;
    692     }
    693   }
    694   return hr;
    695 }
    696 
    697 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path,
    698                                          bool ash_exit) {
    699   DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n";
    700 
    701   if (ash_exit) {
    702     // As we are the top level window, the exiting is done async so we manage
    703     // to execute  the entire function including the final Send().
    704     MetroExit(core_window_hwnd());
    705   }
    706 
    707   // We are just executing delegate_execute here without parameters. Assumption
    708   // here is that this process will be reused by shell when asking for
    709   // IExecuteCommand interface.
    710 
    711   // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
    712   // and place it metro.h or similar accessible file from all code code paths
    713   // using this function.
    714   SHELLEXECUTEINFO sei = { sizeof(sei) };
    715   sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
    716   sei.nShow = SW_SHOWNORMAL;
    717   sei.lpFile = file_path.value().c_str();
    718   sei.lpParameters = NULL;
    719   if (!ash_exit)
    720     sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
    721   ::ShellExecuteExW(&sei);
    722   if (!ash_exit) {
    723     ::TerminateProcess(sei.hProcess, 0);
    724     ::CloseHandle(sei.hProcess);
    725   }
    726 }
    727 
    728 void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut,
    729     const string16& url) {
    730   base::FilePath::StringType file = shortcut.value();
    731   SHELLEXECUTEINFO sei = { sizeof(sei) };
    732   sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
    733   sei.nShow = SW_SHOWNORMAL;
    734   sei.lpFile = file.c_str();
    735   sei.lpDirectory = L"";
    736   sei.lpParameters = url.c_str();
    737   BOOL result = ShellExecuteEx(&sei);
    738 }
    739 
    740 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) {
    741   ::SetCursor(HCURSOR(cursor));
    742 }
    743 
    744 void ChromeAppViewAsh::OnDisplayFileOpenDialog(
    745     const string16& title,
    746     const string16& filter,
    747     const base::FilePath& default_path,
    748     bool allow_multiple_files) {
    749   DVLOG(1) << __FUNCTION__;
    750 
    751   // The OpenFilePickerSession instance is deleted when we receive a
    752   // callback from the OpenFilePickerSession class about the completion of the
    753   // operation.
    754   FilePickerSessionBase* file_picker_ =
    755       new OpenFilePickerSession(this,
    756                                 title,
    757                                 filter,
    758                                 default_path,
    759                                 allow_multiple_files);
    760   file_picker_->Run();
    761 }
    762 
    763 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
    764     const MetroViewerHostMsg_SaveAsDialogParams& params) {
    765   DVLOG(1) << __FUNCTION__;
    766 
    767   // The SaveFilePickerSession instance is deleted when we receive a
    768   // callback from the SaveFilePickerSession class about the completion of the
    769   // operation.
    770   FilePickerSessionBase* file_picker_ =
    771       new SaveFilePickerSession(this, params);
    772   file_picker_->Run();
    773 }
    774 
    775 void ChromeAppViewAsh::OnDisplayFolderPicker(const string16& title) {
    776   DVLOG(1) << __FUNCTION__;
    777   // The FolderPickerSession instance is deleted when we receive a
    778   // callback from the FolderPickerSession class about the completion of the
    779   // operation.
    780   FilePickerSessionBase* file_picker_ = new FolderPickerSession(this, title);
    781   file_picker_->Run();
    782 }
    783 
    784 void ChromeAppViewAsh::OnSetCursorPos(int x, int y) {
    785   if (ui_channel_) {
    786     ::SetCursorPos(x, y);
    787     DVLOG(1) << "In UI OnSetCursorPos: " << x << ", " << y;
    788     ui_channel_->Send(new MetroViewerHostMsg_SetCursorPosAck());
    789     // Generate a fake mouse move which matches the SetCursor coordinates as
    790     // the browser expects to receive a mouse move for these coordinates.
    791     // It is not clear why we don't receive a real mouse move in response to
    792     // the SetCursorPos calll above.
    793     ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(x, y, 0));
    794   }
    795 }
    796 
    797 void ChromeAppViewAsh::OnOpenFileCompleted(
    798     OpenFilePickerSession* open_file_picker,
    799     bool success) {
    800   DVLOG(1) << __FUNCTION__;
    801   DVLOG(1) << "Success: " << success;
    802   if (ui_channel_) {
    803     if (open_file_picker->allow_multi_select()) {
    804       ui_channel_->Send(new MetroViewerHostMsg_MultiFileOpenDone(
    805           success, open_file_picker->filenames()));
    806     } else {
    807       ui_channel_->Send(new MetroViewerHostMsg_FileOpenDone(
    808           success, base::FilePath(open_file_picker->result())));
    809     }
    810   }
    811   delete open_file_picker;
    812 }
    813 
    814 void ChromeAppViewAsh::OnSaveFileCompleted(
    815     SaveFilePickerSession* save_file_picker,
    816     bool success) {
    817   DVLOG(1) << __FUNCTION__;
    818   DVLOG(1) << "Success: " << success;
    819   if (ui_channel_) {
    820     ui_channel_->Send(new MetroViewerHostMsg_FileSaveAsDone(
    821         success,
    822         base::FilePath(save_file_picker->result()),
    823         save_file_picker->filter_index()));
    824   }
    825   delete save_file_picker;
    826 }
    827 
    828 void ChromeAppViewAsh::OnFolderPickerCompleted(
    829     FolderPickerSession* folder_picker,
    830     bool success) {
    831   DVLOG(1) << __FUNCTION__;
    832   DVLOG(1) << "Success: " << success;
    833   if (ui_channel_) {
    834     ui_channel_->Send(new MetroViewerHostMsg_SelectFolderDone(
    835         success,
    836         base::FilePath(folder_picker->result())));
    837   }
    838   delete folder_picker;
    839 }
    840 
    841 void ChromeAppViewAsh::OnImeCancelComposition() {
    842   if (!text_service_)
    843     return;
    844   text_service_->CancelComposition();
    845 }
    846 
    847 void ChromeAppViewAsh::OnImeUpdateTextInputClient(
    848     const std::vector<int32>& input_scopes,
    849     const std::vector<metro_viewer::CharacterBounds>& character_bounds) {
    850   if (!text_service_)
    851     return;
    852   text_service_->OnDocumentChanged(input_scopes, character_bounds);
    853 }
    854 
    855 void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event) {
    856   if (!ui_channel_)
    857     return;
    858   switch (event) {
    859     case ImePopupObserver::kPopupShown:
    860       ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(true));
    861       return;
    862     case ImePopupObserver::kPopupHidden:
    863       ui_channel_->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(false));
    864       return;
    865     case ImePopupObserver::kPopupUpdated:
    866       // TODO(kochi): Support this event for W3C IME API proposal.
    867       // See crbug.com/238585.
    868       return;
    869     default:
    870       NOTREACHED() << "unknown event type: " << event;
    871       return;
    872   }
    873 }
    874 
    875 void ChromeAppViewAsh::OnInputSourceChanged() {
    876   if (!input_source_)
    877     return;
    878 
    879   LANGID langid = 0;
    880   bool is_ime = false;
    881   if (!input_source_->GetActiveSource(&langid, &is_ime)) {
    882     LOG(ERROR) << "GetActiveSource failed";
    883     return;
    884   }
    885   ui_channel_->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid,
    886                                                                  is_ime));
    887 }
    888 
    889 void ChromeAppViewAsh::OnCompositionChanged(
    890     const string16& text,
    891     int32 selection_start,
    892     int32 selection_end,
    893     const std::vector<metro_viewer::UnderlineInfo>& underlines) {
    894   ui_channel_->Send(new MetroViewerHostMsg_ImeCompositionChanged(
    895       text, selection_start, selection_end, underlines));
    896 }
    897 
    898 void ChromeAppViewAsh::OnTextCommitted(const string16& text) {
    899   ui_channel_->Send(new MetroViewerHostMsg_ImeTextCommitted(text));
    900 }
    901 
    902 HRESULT ChromeAppViewAsh::OnActivate(
    903     winapp::Core::ICoreApplicationView*,
    904     winapp::Activation::IActivatedEventArgs* args) {
    905   DVLOG(1) << __FUNCTION__;
    906   // Note: If doing more work in this function, you migth need to call
    907   // get_PreviousExecutionState() and skip the work if  the result is
    908   // ApplicationExecutionState_Running and globals.previous_state is too.
    909   args->get_PreviousExecutionState(&globals.previous_state);
    910   DVLOG(1) << "Previous Execution State: " << globals.previous_state;
    911 
    912   winapp::Activation::ActivationKind activation_kind;
    913   CheckHR(args->get_Kind(&activation_kind));
    914   DVLOG(1) << "Activation kind: " << activation_kind;
    915 
    916   if (activation_kind == winapp::Activation::ActivationKind_Search)
    917     HandleSearchRequest(args);
    918   else if (activation_kind == winapp::Activation::ActivationKind_Protocol)
    919     HandleProtocolRequest(args);
    920   else
    921     LaunchChromeBrowserProcess(NULL, args);
    922   // We call ICoreWindow::Activate after the handling for the search/protocol
    923   // requests because Chrome can be launched to handle a search request which
    924   // in turn launches the chrome browser process in desktop mode via
    925   // ShellExecute. If we call ICoreWindow::Activate before this, then
    926   // Windows kills the metro chrome process when it calls ShellExecute. Seems
    927   // to be a bug.
    928   window_->Activate();
    929   return S_OK;
    930 }
    931 
    932 HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender,
    933                                          winui::Core::IPointerEventArgs* args) {
    934   PointerInfoHandler pointer;
    935   HRESULT hr = pointer.Init(args);
    936   if (FAILED(hr))
    937     return hr;
    938 
    939   if (pointer.IsMouse()) {
    940     ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(
    941         pointer.x(),
    942         pointer.y(),
    943         mouse_down_flags_ | GetKeyboardEventFlags()));
    944   } else {
    945     DCHECK(pointer.IsTouch());
    946     ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(),
    947                                                         pointer.y(),
    948                                                         pointer.timestamp(),
    949                                                         pointer.pointer_id()));
    950   }
    951   return S_OK;
    952 }
    953 
    954 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed
    955 // event for the first button pressed and the last button released in a sequence
    956 // of mouse events.
    957 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
    958 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events.
    959 HRESULT ChromeAppViewAsh::OnPointerPressed(
    960     winui::Core::ICoreWindow* sender,
    961     winui::Core::IPointerEventArgs* args) {
    962   PointerInfoHandler pointer;
    963   HRESULT hr = pointer.Init(args);
    964   if (FAILED(hr))
    965     return hr;
    966 
    967   if (pointer.IsMouse()) {
    968     // TODO: this is wrong, more than one pointer may be down at a time.
    969     mouse_down_flags_ = pointer.flags();
    970     ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
    971         pointer.x(),
    972         pointer.y(),
    973         0,
    974         ui::ET_MOUSE_PRESSED,
    975         static_cast<ui::EventFlags>(
    976             mouse_down_flags_ | GetKeyboardEventFlags())));
    977   } else {
    978     DCHECK(pointer.IsTouch());
    979     ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(),
    980                                                        pointer.y(),
    981                                                        pointer.timestamp(),
    982                                                        pointer.pointer_id()));
    983   }
    984   return S_OK;
    985 }
    986 
    987 HRESULT ChromeAppViewAsh::OnPointerReleased(
    988     winui::Core::ICoreWindow* sender,
    989     winui::Core::IPointerEventArgs* args) {
    990   PointerInfoHandler pointer;
    991   HRESULT hr = pointer.Init(args);
    992   if (FAILED(hr))
    993     return hr;
    994 
    995   if (pointer.IsMouse()) {
    996     // TODO: this is wrong, more than one pointer may be down at a time.
    997     mouse_down_flags_ = ui::EF_NONE;
    998     ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
    999         pointer.x(),
   1000         pointer.y(),
   1001         0,
   1002         ui::ET_MOUSE_RELEASED,
   1003         static_cast<ui::EventFlags>(
   1004             pointer.flags() | GetKeyboardEventFlags())));
   1005   } else {
   1006     DCHECK(pointer.IsTouch());
   1007     ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(),
   1008                                                      pointer.y(),
   1009                                                      pointer.timestamp(),
   1010                                                      pointer.pointer_id()));
   1011   }
   1012   return S_OK;
   1013 }
   1014 
   1015 HRESULT ChromeAppViewAsh::OnWheel(
   1016     winui::Core::ICoreWindow* sender,
   1017     winui::Core::IPointerEventArgs* args) {
   1018   PointerInfoHandler pointer;
   1019   HRESULT hr = pointer.Init(args);
   1020   if (FAILED(hr))
   1021     return hr;
   1022   DCHECK(pointer.IsMouse());
   1023   ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), pointer.y(),
   1024                                                        pointer.wheel_delta(),
   1025                                                        ui::ET_MOUSEWHEEL,
   1026                                                        ui::EF_NONE));
   1027   return S_OK;
   1028 }
   1029 
   1030 HRESULT ChromeAppViewAsh::OnKeyDown(
   1031     winui::Core::ICoreWindow* sender,
   1032     winui::Core::IKeyEventArgs* args) {
   1033   winsys::VirtualKey virtual_key;
   1034   HRESULT hr = args->get_VirtualKey(&virtual_key);
   1035   if (FAILED(hr))
   1036     return hr;
   1037   winui::Core::CorePhysicalKeyStatus status;
   1038   hr = args->get_KeyStatus(&status);
   1039   if (FAILED(hr))
   1040     return hr;
   1041 
   1042   ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
   1043                                                    status.RepeatCount,
   1044                                                    status.ScanCode,
   1045                                                    GetKeyboardEventFlags()));
   1046   return S_OK;
   1047 }
   1048 
   1049 HRESULT ChromeAppViewAsh::OnKeyUp(
   1050     winui::Core::ICoreWindow* sender,
   1051     winui::Core::IKeyEventArgs* args) {
   1052   winsys::VirtualKey virtual_key;
   1053   HRESULT hr = args->get_VirtualKey(&virtual_key);
   1054   if (FAILED(hr))
   1055     return hr;
   1056   winui::Core::CorePhysicalKeyStatus status;
   1057   hr = args->get_KeyStatus(&status);
   1058   if (FAILED(hr))
   1059     return hr;
   1060 
   1061   ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
   1062                                                  status.RepeatCount,
   1063                                                  status.ScanCode,
   1064                                                  GetKeyboardEventFlags()));
   1065   return S_OK;
   1066 }
   1067 
   1068 HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown(
   1069     winui::Core::ICoreDispatcher* sender,
   1070     winui::Core::IAcceleratorKeyEventArgs* args) {
   1071   winsys::VirtualKey virtual_key;
   1072   HRESULT hr = args->get_VirtualKey(&virtual_key);
   1073   if (FAILED(hr))
   1074     return hr;
   1075   winui::Core::CorePhysicalKeyStatus status;
   1076   hr = args->get_KeyStatus(&status);
   1077   if (FAILED(hr))
   1078     return hr;
   1079 
   1080   winui::Core::CoreAcceleratorKeyEventType event_type;
   1081   hr = args->get_EventType(&event_type);
   1082   if (FAILED(hr))
   1083     return hr;
   1084 
   1085   uint32 keyboard_flags = GetKeyboardEventFlags();
   1086 
   1087   switch (event_type) {
   1088     case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter:
   1089       ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key,
   1090                                                          status.RepeatCount,
   1091                                                          status.ScanCode,
   1092                                                          keyboard_flags));
   1093       break;
   1094 
   1095     case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown:
   1096       ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
   1097                                                        status.RepeatCount,
   1098                                                        status.ScanCode,
   1099                                                        keyboard_flags));
   1100       break;
   1101 
   1102     case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp:
   1103       ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
   1104                                                      status.RepeatCount,
   1105                                                      status.ScanCode,
   1106                                                      keyboard_flags));
   1107       break;
   1108 
   1109     default:
   1110       break;
   1111   }
   1112   return S_OK;
   1113 }
   1114 
   1115 HRESULT ChromeAppViewAsh::OnCharacterReceived(
   1116   winui::Core::ICoreWindow* sender,
   1117   winui::Core::ICharacterReceivedEventArgs* args) {
   1118   unsigned int char_code = 0;
   1119   HRESULT hr = args->get_KeyCode(&char_code);
   1120   if (FAILED(hr))
   1121     return hr;
   1122 
   1123   winui::Core::CorePhysicalKeyStatus status;
   1124   hr = args->get_KeyStatus(&status);
   1125   if (FAILED(hr))
   1126     return hr;
   1127 
   1128   ui_channel_->Send(new MetroViewerHostMsg_Character(char_code,
   1129                                                      status.RepeatCount,
   1130                                                      status.ScanCode,
   1131                                                      GetKeyboardEventFlags()));
   1132   return S_OK;
   1133 }
   1134 
   1135 HRESULT ChromeAppViewAsh::OnWindowActivated(
   1136     winui::Core::ICoreWindow* sender,
   1137     winui::Core::IWindowActivatedEventArgs* args) {
   1138   winui::Core::CoreWindowActivationState state;
   1139   HRESULT hr = args->get_WindowActivationState(&state);
   1140   if (FAILED(hr))
   1141     return hr;
   1142 
   1143   // Treat both full activation (Ash was reopened from the Start Screen or from
   1144   // any other Metro entry point in Windows) and pointer activation (user
   1145   // clicked back in Ash after using another app on another monitor) the same.
   1146   if (state == winui::Core::CoreWindowActivationState_CodeActivated ||
   1147       state == winui::Core::CoreWindowActivationState_PointerActivated) {
   1148     if (text_service_)
   1149       text_service_->OnWindowActivated();
   1150     ui_channel_->Send(new MetroViewerHostMsg_WindowActivated());
   1151   }
   1152   return S_OK;
   1153 }
   1154 
   1155 HRESULT ChromeAppViewAsh::HandleSearchRequest(
   1156     winapp::Activation::IActivatedEventArgs* args) {
   1157   mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args;
   1158   CheckHR(args->QueryInterface(
   1159           winapp::Activation::IID_ISearchActivatedEventArgs, &search_args));
   1160 
   1161   if (!ui_channel_) {
   1162     DVLOG(1) << "Launched to handle search request";
   1163     LaunchChromeBrowserProcess(L"--windows8-search", args);
   1164   }
   1165 
   1166   mswrw::HString search_string;
   1167   CheckHR(search_args->get_QueryText(search_string.GetAddressOf()));
   1168   string16 search_text(MakeStdWString(search_string.Get()));
   1169 
   1170   ui_loop_.PostTask(FROM_HERE,
   1171                     base::Bind(&ChromeAppViewAsh::OnSearchRequest,
   1172                     base::Unretained(this),
   1173                     search_text));
   1174   return S_OK;
   1175 }
   1176 
   1177 HRESULT ChromeAppViewAsh::HandleProtocolRequest(
   1178     winapp::Activation::IActivatedEventArgs* args) {
   1179   DVLOG(1) << __FUNCTION__;
   1180   if (!ui_channel_)
   1181     DVLOG(1) << "Launched to handle url request";
   1182 
   1183   mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs>
   1184       protocol_args;
   1185   CheckHR(args->QueryInterface(
   1186           winapp::Activation::IID_IProtocolActivatedEventArgs,
   1187           &protocol_args));
   1188 
   1189   mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
   1190   protocol_args->get_Uri(&uri);
   1191   mswrw::HString url;
   1192   uri->get_AbsoluteUri(url.GetAddressOf());
   1193   string16 actual_url(MakeStdWString(url.Get()));
   1194   DVLOG(1) << "Received url request: " << actual_url;
   1195 
   1196   ui_loop_.PostTask(FROM_HERE,
   1197                     base::Bind(&ChromeAppViewAsh::OnNavigateToUrl,
   1198                                base::Unretained(this),
   1199                                actual_url));
   1200   return S_OK;
   1201 }
   1202 
   1203 HRESULT ChromeAppViewAsh::OnEdgeGestureCompleted(
   1204     winui::Input::IEdgeGesture* gesture,
   1205     winui::Input::IEdgeGestureEventArgs* args) {
   1206   // Swipe from edge gesture (and win+z) is equivalent to pressing F11.
   1207   // TODO(cpu): Make this cleaner for m33.
   1208   ui_channel_->Send(new MetroViewerHostMsg_KeyDown(VK_F11, 1, 0, 0));
   1209   ::Sleep(15);
   1210   ui_channel_->Send(new MetroViewerHostMsg_KeyUp(VK_F11, 1, 0, 0));
   1211   return S_OK;
   1212 }
   1213 
   1214 void ChromeAppViewAsh::OnSearchRequest(const string16& search_string) {
   1215   DCHECK(ui_channel_);
   1216   ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string));
   1217 }
   1218 
   1219 void ChromeAppViewAsh::OnNavigateToUrl(const string16& url) {
   1220   DCHECK(ui_channel_);
   1221  ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url));
   1222 }
   1223 
   1224 HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender,
   1225     winui::Core::IWindowSizeChangedEventArgs* args) {
   1226   if (!window_) {
   1227     return S_OK;
   1228   }
   1229 
   1230   winfoundtn::Size size;
   1231   HRESULT hr = args->get_Size(&size);
   1232   if (FAILED(hr))
   1233     return hr;
   1234 
   1235   uint32 cx = static_cast<uint32>(size.Width);
   1236   uint32 cy = static_cast<uint32>(size.Height);
   1237 
   1238   DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy;
   1239   ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy));
   1240   return S_OK;
   1241 }
   1242 
   1243 ///////////////////////////////////////////////////////////////////////////////
   1244 
   1245 ChromeAppViewFactory::ChromeAppViewFactory(
   1246     winapp::Core::ICoreApplication* icore_app,
   1247     LPTHREAD_START_ROUTINE host_main,
   1248     void* host_context) {
   1249   mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
   1250   mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
   1251   CheckHR(core_app.As(&app_exit));
   1252   globals.app_exit = app_exit.Detach();
   1253 }
   1254 
   1255 IFACEMETHODIMP
   1256 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
   1257   *view = mswr::Make<ChromeAppViewAsh>().Detach();
   1258   return (*view) ? S_OK :  E_OUTOFMEMORY;
   1259 }
   1260