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