Ignore title parameter for navigator.registerProtocolHandler
[chromium-blink-merge.git] / win8 / metro_driver / chrome_app_view_ash.cc
bloba82ab1f6fe22580e8cd696b97657ae14fb5a9506
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.
5 #include "win8/metro_driver/stdafx.h"
6 #include "win8/metro_driver/chrome_app_view_ash.h"
8 #include <corewindow.h>
9 #include <shellapi.h>
10 #include <windows.foundation.h>
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 "base/win/windows_version.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "ipc/ipc_channel.h"
23 #include "ipc/ipc_channel_proxy.h"
24 #include "ipc/ipc_sender.h"
25 #include "ui/events/gestures/gesture_sequence.h"
26 #include "ui/metro_viewer/metro_viewer_messages.h"
27 #include "win8/metro_driver/file_picker_ash.h"
28 #include "win8/metro_driver/ime/ime_popup_monitor.h"
29 #include "win8/metro_driver/ime/input_source.h"
30 #include "win8/metro_driver/ime/text_service.h"
31 #include "win8/metro_driver/metro_driver.h"
32 #include "win8/metro_driver/winrt_utils.h"
33 #include "win8/viewer/metro_viewer_constants.h"
35 typedef winfoundtn::ITypedEventHandler<
36 winapp::Core::CoreApplicationView*,
37 winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
39 typedef winfoundtn::ITypedEventHandler<
40 winui::Core::CoreWindow*,
41 winui::Core::PointerEventArgs*> PointerEventHandler;
43 typedef winfoundtn::ITypedEventHandler<
44 winui::Core::CoreWindow*,
45 winui::Core::KeyEventArgs*> KeyEventHandler;
47 typedef winfoundtn::ITypedEventHandler<
48 winui::Core::CoreDispatcher*,
49 winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler;
51 typedef winfoundtn::ITypedEventHandler<
52 winui::Core::CoreWindow*,
53 winui::Core::CharacterReceivedEventArgs*> CharEventHandler;
55 typedef winfoundtn::ITypedEventHandler<
56 winui::Core::CoreWindow*,
57 winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler;
59 typedef winfoundtn::ITypedEventHandler<
60 winui::Core::CoreWindow*,
61 winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
63 typedef winfoundtn::ITypedEventHandler<
64 winui::Input::EdgeGesture*,
65 winui::Input::EdgeGestureEventArgs*> EdgeEventHandler;
67 // This function is exported by chrome.exe.
68 typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info);
70 // Global information used across the metro driver.
71 struct Globals {
72 winapp::Activation::ApplicationExecutionState previous_state;
73 winapp::Core::ICoreApplicationExit* app_exit;
74 BreakpadExceptionHandler breakpad_exception_handler;
75 } globals;
77 namespace {
79 enum KeyModifier {
80 NONE,
81 SHIFT = 1,
82 CONTROL = 2,
83 ALT = 4
86 // Helper function to send keystrokes via the SendInput function.
87 // mnemonic_char: The keystroke to be sent.
88 // modifiers: Combination with Alt, Ctrl, Shift, etc.
89 void SendKeySequence(
90 WORD mnemonic_char, KeyModifier modifiers) {
91 INPUT keys[4] = {0}; // Keyboard events
92 int key_count = 0; // Number of generated events
94 if (modifiers & SHIFT) {
95 keys[key_count].type = INPUT_KEYBOARD;
96 keys[key_count].ki.wVk = VK_SHIFT;
97 keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
98 key_count++;
101 if (modifiers & CONTROL) {
102 keys[key_count].type = INPUT_KEYBOARD;
103 keys[key_count].ki.wVk = VK_CONTROL;
104 keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
105 key_count++;
108 if (modifiers & ALT) {
109 keys[key_count].type = INPUT_KEYBOARD;
110 keys[key_count].ki.wVk = VK_MENU;
111 keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
112 key_count++;
115 keys[key_count].type = INPUT_KEYBOARD;
116 keys[key_count].ki.wVk = mnemonic_char;
117 keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
118 key_count++;
120 bool should_sleep = key_count > 1;
122 // Send key downs.
123 for (int i = 0; i < key_count; i++) {
124 SendInput(1, &keys[ i ], sizeof(keys[0]));
125 keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
126 if (should_sleep)
127 Sleep(10);
130 // Now send key ups in reverse order.
131 for (int i = key_count; i; i--) {
132 SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
133 if (should_sleep)
134 Sleep(10);
138 class ChromeChannelListener : public IPC::Listener {
139 public:
140 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
141 : ui_proxy_(ui_loop->message_loop_proxy()),
142 app_view_(app_view) {}
144 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
145 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
146 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop,
147 OnActivateDesktop)
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit, OnMetroExit)
149 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop,
150 OnOpenURLOnDesktop)
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
152 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen,
153 OnDisplayFileOpenDialog)
154 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs,
155 OnDisplayFileSaveAsDialog)
156 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder,
157 OnDisplayFolderPicker)
158 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos)
159 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition,
160 OnImeCancelComposition)
161 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated,
162 OnImeTextInputClientChanged)
163 IPC_MESSAGE_UNHANDLED(__debugbreak())
164 IPC_END_MESSAGE_MAP()
165 return true;
168 virtual void OnChannelError() OVERRIDE {
169 DVLOG(1) << "Channel error. Exiting.";
170 ui_proxy_->PostTask(FROM_HERE,
171 base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_),
172 TERMINATE_USING_KEY_SEQUENCE));
174 // In early Windows 8 versions the code above sometimes fails so we call
175 // it a second time with a NULL window which just calls Exit().
176 ui_proxy_->PostDelayedTask(FROM_HERE,
177 base::Bind(&ChromeAppViewAsh::OnMetroExit, base::Unretained(app_view_),
178 TERMINATE_USING_PROCESS_EXIT),
179 base::TimeDelta::FromMilliseconds(100));
182 private:
183 void OnActivateDesktop(const base::FilePath& shortcut, bool ash_exit) {
184 ui_proxy_->PostTask(FROM_HERE,
185 base::Bind(&ChromeAppViewAsh::OnActivateDesktop,
186 base::Unretained(app_view_),
187 shortcut, ash_exit));
190 void OnMetroExit() {
191 ui_proxy_->PostTask(FROM_HERE,
192 base::Bind(&ChromeAppViewAsh::OnMetroExit,
193 base::Unretained(app_view_), TERMINATE_USING_KEY_SEQUENCE));
196 void OnOpenURLOnDesktop(const base::FilePath& shortcut,
197 const base::string16& url) {
198 ui_proxy_->PostTask(FROM_HERE,
199 base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop,
200 base::Unretained(app_view_),
201 shortcut, url));
204 void OnSetCursor(int64 cursor) {
205 ui_proxy_->PostTask(FROM_HERE,
206 base::Bind(&ChromeAppViewAsh::OnSetCursor,
207 base::Unretained(app_view_),
208 reinterpret_cast<HCURSOR>(cursor)));
211 void OnDisplayFileOpenDialog(const base::string16& title,
212 const base::string16& filter,
213 const base::FilePath& default_path,
214 bool allow_multiple_files) {
215 ui_proxy_->PostTask(FROM_HERE,
216 base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog,
217 base::Unretained(app_view_),
218 title,
219 filter,
220 default_path,
221 allow_multiple_files));
224 void OnDisplayFileSaveAsDialog(
225 const MetroViewerHostMsg_SaveAsDialogParams& params) {
226 ui_proxy_->PostTask(
227 FROM_HERE,
228 base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog,
229 base::Unretained(app_view_),
230 params));
233 void OnDisplayFolderPicker(const base::string16& title) {
234 ui_proxy_->PostTask(
235 FROM_HERE,
236 base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker,
237 base::Unretained(app_view_),
238 title));
241 void OnSetCursorPos(int x, int y) {
242 VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y;
243 ui_proxy_->PostTask(
244 FROM_HERE,
245 base::Bind(&ChromeAppViewAsh::OnSetCursorPos,
246 base::Unretained(app_view_),
247 x, y));
250 void OnImeCancelComposition() {
251 ui_proxy_->PostTask(
252 FROM_HERE,
253 base::Bind(&ChromeAppViewAsh::OnImeCancelComposition,
254 base::Unretained(app_view_)));
257 void OnImeTextInputClientChanged(
258 const std::vector<int32>& input_scopes,
259 const std::vector<metro_viewer::CharacterBounds>& character_bounds) {
260 ui_proxy_->PostTask(
261 FROM_HERE,
262 base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient,
263 base::Unretained(app_view_),
264 input_scopes,
265 character_bounds));
268 scoped_refptr<base::MessageLoopProxy> ui_proxy_;
269 ChromeAppViewAsh* app_view_;
272 bool WaitForChromeIPCConnection(const std::string& channel_name) {
273 int ms_elapsed = 0;
274 while (!IPC::Channel::IsNamedServerInitialized(channel_name) &&
275 ms_elapsed < 10000) {
276 ms_elapsed += 100;
277 Sleep(100);
279 return IPC::Channel::IsNamedServerInitialized(channel_name);
282 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
283 // We're entering a nested message loop, let's allow dispatching
284 // tasks while we're in there.
285 base::MessageLoop::current()->SetNestableTasksAllowed(true);
287 // Enter main core message loop. There are several ways to exit it
288 // Nicely:
289 // 1 - User action like ALT-F4.
290 // 2 - Calling ICoreApplicationExit::Exit().
291 // 3- Posting WM_CLOSE to the core window.
292 HRESULT hr = dispatcher->ProcessEvents(
293 winui::Core::CoreProcessEventsOption
294 ::CoreProcessEventsOption_ProcessUntilQuit);
296 // Wind down the thread's chrome message loop.
297 base::MessageLoop::current()->Quit();
300 // Helper to return the state of the shift/control/alt keys.
301 uint32 GetKeyboardEventFlags() {
302 uint32 flags = 0;
303 if (base::win::IsShiftPressed())
304 flags |= ui::EF_SHIFT_DOWN;
305 if (base::win::IsCtrlPressed())
306 flags |= ui::EF_CONTROL_DOWN;
307 if (base::win::IsAltPressed())
308 flags |= ui::EF_ALT_DOWN;
309 return flags;
312 bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters,
313 winapp::Activation::IActivatedEventArgs* args) {
314 if (args) {
315 DVLOG(1) << __FUNCTION__ << ":" << ::GetCommandLineW();
316 winapp::Activation::ActivationKind activation_kind;
317 CheckHR(args->get_Kind(&activation_kind));
319 DVLOG(1) << __FUNCTION__ << ", activation_kind=" << activation_kind;
321 if (activation_kind == winapp::Activation::ActivationKind_Launch) {
322 mswr::ComPtr<winapp::Activation::ILaunchActivatedEventArgs> launch_args;
323 if (args->QueryInterface(
324 winapp::Activation::IID_ILaunchActivatedEventArgs,
325 &launch_args) == S_OK) {
326 DVLOG(1) << "Activate: ActivationKind_Launch";
327 mswrw::HString launch_args_str;
328 launch_args->get_Arguments(launch_args_str.GetAddressOf());
329 base::string16 actual_launch_args(
330 MakeStdWString(launch_args_str.Get()));
331 if (actual_launch_args == win8::kMetroViewerConnectVerb) {
332 DVLOG(1) << __FUNCTION__ << "Not launching chrome server";
333 return true;
339 DVLOG(1) << "Launching chrome server";
340 base::FilePath chrome_exe_path;
342 if (!PathService::Get(base::FILE_EXE, &chrome_exe_path))
343 return false;
345 base::string16 parameters = L"--silent-launch --viewer-connect ";
346 if (additional_parameters)
347 parameters += additional_parameters;
349 SHELLEXECUTEINFO sei = { sizeof(sei) };
350 sei.nShow = SW_SHOWNORMAL;
351 sei.lpFile = chrome_exe_path.value().c_str();
352 sei.lpDirectory = L"";
353 sei.lpParameters = parameters.c_str();
354 ::ShellExecuteEx(&sei);
355 return true;
358 } // namespace
360 // This class helps decoding the pointer properties of an event.
361 class ChromeAppViewAsh::PointerInfoHandler {
362 public:
363 PointerInfoHandler()
364 : x_(0),
365 y_(0),
366 wheel_delta_(0),
367 update_kind_(winui::Input::PointerUpdateKind_Other),
368 timestamp_(0),
369 pointer_id_(0),
370 mouse_down_flags_(0),
371 is_horizontal_wheel_(0) {}
373 HRESULT Init(winui::Core::IPointerEventArgs* args) {
374 HRESULT hr = args->get_CurrentPoint(&pointer_point_);
375 if (FAILED(hr))
376 return hr;
378 winfoundtn::Point point;
379 hr = pointer_point_->get_Position(&point);
380 if (FAILED(hr))
381 return hr;
383 mswr::ComPtr<winui::Input::IPointerPointProperties> properties;
384 hr = pointer_point_->get_Properties(&properties);
385 if (FAILED(hr))
386 return hr;
388 hr = properties->get_PointerUpdateKind(&update_kind_);
389 if (FAILED(hr))
390 return hr;
392 hr = properties->get_MouseWheelDelta(&wheel_delta_);
393 if (FAILED(hr))
394 return hr;
396 is_horizontal_wheel_ = 0;
397 properties->get_IsHorizontalMouseWheel(&is_horizontal_wheel_);
399 x_ = point.X;
400 y_ = point.Y;
402 pointer_point_->get_Timestamp(&timestamp_);
403 pointer_point_->get_PointerId(&pointer_id_);
404 // Map the OS touch event id to a range allowed by the gesture recognizer.
405 if (IsTouch())
406 pointer_id_ %= ui::GestureSequence::kMaxGesturePoints;
408 boolean left_button_state;
409 hr = properties->get_IsLeftButtonPressed(&left_button_state);
410 if (FAILED(hr))
411 return hr;
412 if (left_button_state)
413 mouse_down_flags_ |= ui::EF_LEFT_MOUSE_BUTTON;
415 boolean right_button_state;
416 hr = properties->get_IsRightButtonPressed(&right_button_state);
417 if (FAILED(hr))
418 return hr;
419 if (right_button_state)
420 mouse_down_flags_ |= ui::EF_RIGHT_MOUSE_BUTTON;
422 boolean middle_button_state;
423 hr = properties->get_IsMiddleButtonPressed(&middle_button_state);
424 if (FAILED(hr))
425 return hr;
426 if (middle_button_state)
427 mouse_down_flags_ |= ui::EF_MIDDLE_MOUSE_BUTTON;
429 return S_OK;
432 bool IsType(windevs::Input::PointerDeviceType type) const {
433 mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device;
434 CheckHR(pointer_point_->get_PointerDevice(&pointer_device));
435 windevs::Input::PointerDeviceType device_type;
436 CheckHR(pointer_device->get_PointerDeviceType(&device_type));
437 return (device_type == type);
440 bool IsMouse() const {
441 return IsType(windevs::Input::PointerDeviceType_Mouse);
444 bool IsTouch() const {
445 return IsType(windevs::Input::PointerDeviceType_Touch);
448 int32 wheel_delta() const {
449 return wheel_delta_;
452 // Identifies the button that changed.
453 ui::EventFlags changed_button() const {
454 switch (update_kind_) {
455 case winui::Input::PointerUpdateKind_LeftButtonPressed:
456 return ui::EF_LEFT_MOUSE_BUTTON;
457 case winui::Input::PointerUpdateKind_LeftButtonReleased:
458 return ui::EF_LEFT_MOUSE_BUTTON;
459 case winui::Input::PointerUpdateKind_RightButtonPressed:
460 return ui::EF_RIGHT_MOUSE_BUTTON;
461 case winui::Input::PointerUpdateKind_RightButtonReleased:
462 return ui::EF_RIGHT_MOUSE_BUTTON;
463 case winui::Input::PointerUpdateKind_MiddleButtonPressed:
464 return ui::EF_MIDDLE_MOUSE_BUTTON;
465 case winui::Input::PointerUpdateKind_MiddleButtonReleased:
466 return ui::EF_MIDDLE_MOUSE_BUTTON;
467 default:
468 return ui::EF_NONE;
472 uint32 mouse_down_flags() const { return mouse_down_flags_; }
474 int x() const { return x_; }
475 int y() const { return y_; }
477 uint32 pointer_id() const {
478 return pointer_id_;
481 uint64 timestamp() const { return timestamp_; }
483 winui::Input::PointerUpdateKind update_kind() const { return update_kind_; }
485 bool is_horizontal_wheel() const { return !!is_horizontal_wheel_; }
487 private:
488 int x_;
489 int y_;
490 int wheel_delta_;
491 uint32 pointer_id_;
492 winui::Input::PointerUpdateKind update_kind_;
493 mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_;
494 uint64 timestamp_;
496 // Bitmask of ui::EventFlags corresponding to the buttons that are currently
497 // down.
498 uint32 mouse_down_flags_;
500 // Set to true for a horizontal wheel message.
501 boolean is_horizontal_wheel_;
503 DISALLOW_COPY_AND_ASSIGN(PointerInfoHandler);
506 ChromeAppViewAsh::ChromeAppViewAsh()
507 : mouse_down_flags_(ui::EF_NONE),
508 ui_channel_(nullptr),
509 core_window_hwnd_(NULL) {
510 DVLOG(1) << __FUNCTION__;
511 globals.previous_state =
512 winapp::Activation::ApplicationExecutionState_NotRunning;
515 ChromeAppViewAsh::~ChromeAppViewAsh() {
516 DVLOG(1) << __FUNCTION__;
519 IFACEMETHODIMP
520 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) {
521 view_ = view;
522 DVLOG(1) << __FUNCTION__;
523 HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
524 this, &ChromeAppViewAsh::OnActivate).Get(),
525 &activated_token_);
526 CheckHR(hr);
527 return hr;
530 IFACEMETHODIMP
531 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) {
532 window_ = window;
533 DVLOG(1) << __FUNCTION__;
535 // Retrieve the native window handle via the interop layer.
536 mswr::ComPtr<ICoreWindowInterop> interop;
537 HRESULT hr = window->QueryInterface(interop.GetAddressOf());
538 CheckHR(hr);
539 hr = interop->get_WindowHandle(&core_window_hwnd_);
540 CheckHR(hr);
542 text_service_ = metro_driver::CreateTextService(this, core_window_hwnd_);
544 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
545 this, &ChromeAppViewAsh::OnSizeChanged).Get(),
546 &sizechange_token_);
547 CheckHR(hr);
549 // Register for pointer and keyboard notifications. We forward
550 // them to the browser process via IPC.
551 hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>(
552 this, &ChromeAppViewAsh::OnPointerMoved).Get(),
553 &pointermoved_token_);
554 CheckHR(hr);
556 hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>(
557 this, &ChromeAppViewAsh::OnPointerPressed).Get(),
558 &pointerpressed_token_);
559 CheckHR(hr);
561 hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>(
562 this, &ChromeAppViewAsh::OnPointerReleased).Get(),
563 &pointerreleased_token_);
564 CheckHR(hr);
566 hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>(
567 this, &ChromeAppViewAsh::OnKeyDown).Get(),
568 &keydown_token_);
569 CheckHR(hr);
571 hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>(
572 this, &ChromeAppViewAsh::OnKeyUp).Get(),
573 &keyup_token_);
574 CheckHR(hr);
576 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
577 hr = window_->get_Dispatcher(dispatcher.GetAddressOf());
578 CheckHR(hr, "Get Dispatcher failed.");
580 mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys;
581 hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys),
582 reinterpret_cast<void**>(
583 accelerator_keys.GetAddressOf()));
584 CheckHR(hr, "QI for ICoreAcceleratorKeys failed.");
585 hr = accelerator_keys->add_AcceleratorKeyActivated(
586 mswr::Callback<AcceleratorKeyEventHandler>(
587 this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(),
588 &accel_keydown_token_);
589 CheckHR(hr);
591 hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>(
592 this, &ChromeAppViewAsh::OnWheel).Get(),
593 &wheel_token_);
594 CheckHR(hr);
596 hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>(
597 this, &ChromeAppViewAsh::OnCharacterReceived).Get(),
598 &character_received_token_);
599 CheckHR(hr);
601 hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>(
602 this, &ChromeAppViewAsh::OnWindowActivated).Get(),
603 &window_activated_token_);
604 CheckHR(hr);
606 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
607 // Register for edge gesture notifications only for Windows 8 and above.
608 mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics;
609 hr = winrt_utils::CreateActivationFactory(
610 RuntimeClass_Windows_UI_Input_EdgeGesture,
611 edge_gesture_statics.GetAddressOf());
612 CheckHR(hr);
614 mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture;
615 hr = edge_gesture_statics->GetForCurrentView(&edge_gesture);
616 CheckHR(hr);
618 hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>(
619 this, &ChromeAppViewAsh::OnEdgeGestureCompleted).Get(),
620 &edgeevent_token_);
621 CheckHR(hr);
624 // By initializing the direct 3D swap chain with the corewindow
625 // we can now directly blit to it from the browser process.
626 direct3d_helper_.Initialize(window);
627 DVLOG(1) << "Initialized Direct3D.";
628 return S_OK;
631 IFACEMETHODIMP
632 ChromeAppViewAsh::Load(HSTRING entryPoint) {
633 // On Win7 |entryPoint| is NULL.
634 DVLOG(1) << __FUNCTION__;
635 return S_OK;
638 IFACEMETHODIMP
639 ChromeAppViewAsh::Run() {
640 DVLOG(1) << __FUNCTION__;
641 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
642 HRESULT hr = window_->get_Dispatcher(dispatcher.GetAddressOf());
643 CheckHR(hr, "Dispatcher failed.");
645 hr = window_->Activate();
646 if (FAILED(hr)) {
647 DLOG(WARNING) << "activation failed hr=" << hr;
648 return hr;
651 // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
652 base::Thread io_thread("metro_IO_thread");
653 base::Thread::Options options;
654 options.message_loop_type = base::MessageLoop::TYPE_IO;
655 io_thread.StartWithOptions(options);
657 // Start up Chrome and wait for the desired IPC server connection to exist.
658 WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName);
660 // In Aura mode we create an IPC channel to the browser, then ask it to
661 // connect to us.
662 ChromeChannelListener ui_channel_listener(&ui_loop_, this);
663 IPC::ChannelProxy ui_channel(win8::kMetroViewerIPCChannelName,
664 IPC::Channel::MODE_NAMED_CLIENT,
665 &ui_channel_listener,
666 io_thread.message_loop_proxy());
667 ui_channel_ = &ui_channel;
669 // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
670 // browser will use D3D from the browser process to present to our Window.
671 ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface(
672 gfx::NativeViewId(core_window_hwnd_)));
673 DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_;
675 // Send an initial size message so that the Ash root window host gets sized
676 // correctly.
677 RECT rect = {0};
678 ::GetWindowRect(core_window_hwnd_, &rect);
679 ui_channel_->Send(
680 new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left,
681 rect.bottom - rect.top));
683 input_source_ = metro_driver::InputSource::Create();
684 if (input_source_) {
685 input_source_->AddObserver(this);
686 // Send an initial input source.
687 OnInputSourceChanged();
690 // Start receiving IME popup window notifications.
691 metro_driver::AddImePopupObserver(this);
693 // And post the task that'll do the inner Metro message pumping to it.
694 ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
695 ui_loop_.Run();
697 DVLOG(0) << "ProcessEvents done, hr=" << hr;
698 return hr;
701 IFACEMETHODIMP
702 ChromeAppViewAsh::Uninitialize() {
703 DVLOG(1) << __FUNCTION__;
704 metro_driver::RemoveImePopupObserver(this);
705 input_source_.reset();
706 text_service_.reset();
707 window_ = nullptr;
708 view_ = nullptr;
709 core_window_hwnd_ = NULL;
710 return S_OK;
713 // static
714 HRESULT ChromeAppViewAsh::Unsnap() {
715 mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
716 HRESULT hr = winrt_utils::CreateActivationFactory(
717 RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
718 view_statics.GetAddressOf());
719 CheckHR(hr);
721 winui::ViewManagement::ApplicationViewState state =
722 winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
723 hr = view_statics->get_Value(&state);
724 CheckHR(hr);
726 if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
727 boolean success = FALSE;
728 hr = view_statics->TryUnsnap(&success);
730 if (FAILED(hr) || !success) {
731 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
732 if (SUCCEEDED(hr))
733 hr = E_UNEXPECTED;
736 return hr;
739 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path,
740 bool ash_exit) {
741 DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n";
743 if (ash_exit) {
744 // As we are the top level window, the exiting is done async so we manage
745 // to execute the entire function including the final Send().
746 OnMetroExit(TERMINATE_USING_KEY_SEQUENCE);
749 // We are just executing delegate_execute here without parameters. Assumption
750 // here is that this process will be reused by shell when asking for
751 // IExecuteCommand interface.
753 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
754 // and place it metro.h or similar accessible file from all code code paths
755 // using this function.
756 SHELLEXECUTEINFO sei = { sizeof(sei) };
757 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
758 sei.nShow = SW_SHOWNORMAL;
759 sei.lpFile = file_path.value().c_str();
760 sei.lpParameters = NULL;
761 if (!ash_exit)
762 sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
763 ::ShellExecuteExW(&sei);
764 if (!ash_exit) {
765 ::TerminateProcess(sei.hProcess, 0);
766 ::CloseHandle(sei.hProcess);
770 void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut,
771 const base::string16& url) {
772 base::FilePath::StringType file = shortcut.value();
773 SHELLEXECUTEINFO sei = { sizeof(sei) };
774 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
775 sei.nShow = SW_SHOWNORMAL;
776 sei.lpFile = file.c_str();
777 sei.lpDirectory = L"";
778 sei.lpParameters = url.c_str();
779 BOOL result = ShellExecuteEx(&sei);
782 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) {
783 ::SetCursor(HCURSOR(cursor));
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__;
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();
805 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
806 const MetroViewerHostMsg_SaveAsDialogParams& params) {
807 DVLOG(1) << __FUNCTION__;
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();
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();
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));
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())));
853 delete open_file_picker;
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()));
867 delete save_file_picker;
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())));
880 delete folder_picker;
883 void ChromeAppViewAsh::OnImeCancelComposition() {
884 if (!text_service_)
885 return;
886 text_service_->CancelComposition();
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);
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;
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);
930 if (ui_channel_)
931 ui_channel_->Close();
933 globals.app_exit->Exit();
936 void ChromeAppViewAsh::OnInputSourceChanged() {
937 if (!input_source_)
938 return;
940 LANGID langid = 0;
941 bool is_ime = false;
942 if (!input_source_->GetActiveSource(&langid, &is_ime)) {
943 LOG(ERROR) << "GetActiveSource failed";
944 return;
946 ui_channel_->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid,
947 is_ime));
950 void ChromeAppViewAsh::OnCompositionChanged(
951 const base::string16& text,
952 int32 selection_start,
953 int32 selection_end,
954 const std::vector<metro_viewer::UnderlineInfo>& underlines) {
955 ui_channel_->Send(new MetroViewerHostMsg_ImeCompositionChanged(
956 text, selection_start, selection_end, underlines));
959 void ChromeAppViewAsh::OnTextCommitted(const base::string16& text) {
960 ui_channel_->Send(new MetroViewerHostMsg_ImeTextCommitted(text));
963 void ChromeAppViewAsh::SendMouseButton(int x,
964 int y,
965 int extra,
966 ui::EventType event_type,
967 uint32 flags,
968 ui::EventFlags changed_button,
969 bool is_horizontal_wheel) {
970 MetroViewerHostMsg_MouseButtonParams params;
971 params.x = static_cast<int32>(x);
972 params.y = static_cast<int32>(y);
973 params.extra = static_cast<int32>(extra);
974 params.event_type = event_type;
975 params.flags = static_cast<int32>(flags);
976 params.changed_button = changed_button;
977 params.is_horizontal_wheel = is_horizontal_wheel;
978 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(params));
981 void ChromeAppViewAsh::GenerateMouseEventFromMoveIfNecessary(
982 const PointerInfoHandler& pointer) {
983 ui::EventType event_type;
984 // For aura we want the flags to include the button that was released, thus
985 // we or the old and new.
986 uint32 mouse_down_flags = pointer.mouse_down_flags() | mouse_down_flags_;
987 mouse_down_flags_ = pointer.mouse_down_flags();
988 switch (pointer.update_kind()) {
989 case winui::Input::PointerUpdateKind_LeftButtonPressed:
990 case winui::Input::PointerUpdateKind_RightButtonPressed:
991 case winui::Input::PointerUpdateKind_MiddleButtonPressed:
992 event_type = ui::ET_MOUSE_PRESSED;
993 break;
994 case winui::Input::PointerUpdateKind_LeftButtonReleased:
995 case winui::Input::PointerUpdateKind_RightButtonReleased:
996 case winui::Input::PointerUpdateKind_MiddleButtonReleased:
997 event_type = ui::ET_MOUSE_RELEASED;
998 break;
999 default:
1000 return;
1002 SendMouseButton(pointer.x(), pointer.y(), 0, event_type,
1003 mouse_down_flags | GetKeyboardEventFlags(),
1004 pointer.changed_button(), pointer.is_horizontal_wheel());
1007 HRESULT ChromeAppViewAsh::OnActivate(
1008 winapp::Core::ICoreApplicationView*,
1009 winapp::Activation::IActivatedEventArgs* args) {
1010 DVLOG(1) << __FUNCTION__;
1011 // Note: If doing more work in this function, you migth need to call
1012 // get_PreviousExecutionState() and skip the work if the result is
1013 // ApplicationExecutionState_Running and globals.previous_state is too.
1014 args->get_PreviousExecutionState(&globals.previous_state);
1015 DVLOG(1) << "Previous Execution State: " << globals.previous_state;
1017 winapp::Activation::ActivationKind activation_kind;
1018 CheckHR(args->get_Kind(&activation_kind));
1019 DVLOG(1) << "Activation kind: " << activation_kind;
1021 if (activation_kind == winapp::Activation::ActivationKind_Search)
1022 HandleSearchRequest(args);
1023 else if (activation_kind == winapp::Activation::ActivationKind_Protocol)
1024 HandleProtocolRequest(args);
1025 else
1026 LaunchChromeBrowserProcess(NULL, args);
1027 // We call ICoreWindow::Activate after the handling for the search/protocol
1028 // requests because Chrome can be launched to handle a search request which
1029 // in turn launches the chrome browser process in desktop mode via
1030 // ShellExecute. If we call ICoreWindow::Activate before this, then
1031 // Windows kills the metro chrome process when it calls ShellExecute. Seems
1032 // to be a bug.
1033 window_->Activate();
1034 return S_OK;
1037 HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender,
1038 winui::Core::IPointerEventArgs* args) {
1039 PointerInfoHandler pointer;
1040 HRESULT hr = pointer.Init(args);
1041 if (FAILED(hr))
1042 return hr;
1044 if (pointer.IsMouse()) {
1045 GenerateMouseEventFromMoveIfNecessary(pointer);
1046 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(
1047 pointer.x(),
1048 pointer.y(),
1049 mouse_down_flags_ | GetKeyboardEventFlags()));
1050 } else {
1051 DCHECK(pointer.IsTouch());
1052 ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(),
1053 pointer.y(),
1054 pointer.timestamp(),
1055 pointer.pointer_id()));
1057 return S_OK;
1060 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed
1061 // event for the first button pressed and the last button released in a sequence
1062 // of mouse events.
1063 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
1064 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. Intermediary
1065 // presses and releases are tracked in OnPointMoved().
1066 HRESULT ChromeAppViewAsh::OnPointerPressed(
1067 winui::Core::ICoreWindow* sender,
1068 winui::Core::IPointerEventArgs* args) {
1069 PointerInfoHandler pointer;
1070 HRESULT hr = pointer.Init(args);
1071 if (FAILED(hr))
1072 return hr;
1074 if (pointer.IsMouse()) {
1075 mouse_down_flags_ = pointer.mouse_down_flags();
1076 SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_PRESSED,
1077 mouse_down_flags_ | GetKeyboardEventFlags(),
1078 pointer.changed_button(), pointer.is_horizontal_wheel());
1079 } else {
1080 DCHECK(pointer.IsTouch());
1081 ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(),
1082 pointer.y(),
1083 pointer.timestamp(),
1084 pointer.pointer_id()));
1086 return S_OK;
1089 HRESULT ChromeAppViewAsh::OnPointerReleased(
1090 winui::Core::ICoreWindow* sender,
1091 winui::Core::IPointerEventArgs* args) {
1092 PointerInfoHandler pointer;
1093 HRESULT hr = pointer.Init(args);
1094 if (FAILED(hr))
1095 return hr;
1097 if (pointer.IsMouse()) {
1098 mouse_down_flags_ = ui::EF_NONE;
1099 SendMouseButton(pointer.x(), pointer.y(), 0, ui::ET_MOUSE_RELEASED,
1100 static_cast<uint32>(pointer.changed_button()) |
1101 GetKeyboardEventFlags(),
1102 pointer.changed_button(),
1103 pointer.is_horizontal_wheel());
1104 } else {
1105 DCHECK(pointer.IsTouch());
1106 ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(),
1107 pointer.y(),
1108 pointer.timestamp(),
1109 pointer.pointer_id()));
1111 return S_OK;
1114 HRESULT ChromeAppViewAsh::OnWheel(
1115 winui::Core::ICoreWindow* sender,
1116 winui::Core::IPointerEventArgs* args) {
1117 PointerInfoHandler pointer;
1118 HRESULT hr = pointer.Init(args);
1119 if (FAILED(hr))
1120 return hr;
1121 DCHECK(pointer.IsMouse());
1122 SendMouseButton(pointer.x(), pointer.y(), pointer.wheel_delta(),
1123 ui::ET_MOUSEWHEEL, ui::EF_NONE, ui::EF_NONE,
1124 pointer.is_horizontal_wheel());
1125 return S_OK;
1128 HRESULT ChromeAppViewAsh::OnKeyDown(
1129 winui::Core::ICoreWindow* sender,
1130 winui::Core::IKeyEventArgs* args) {
1131 winsys::VirtualKey virtual_key;
1132 HRESULT hr = args->get_VirtualKey(&virtual_key);
1133 if (FAILED(hr))
1134 return hr;
1135 winui::Core::CorePhysicalKeyStatus status;
1136 hr = args->get_KeyStatus(&status);
1137 if (FAILED(hr))
1138 return hr;
1140 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
1141 status.RepeatCount,
1142 status.ScanCode,
1143 GetKeyboardEventFlags()));
1144 return S_OK;
1147 HRESULT ChromeAppViewAsh::OnKeyUp(
1148 winui::Core::ICoreWindow* sender,
1149 winui::Core::IKeyEventArgs* args) {
1150 winsys::VirtualKey virtual_key;
1151 HRESULT hr = args->get_VirtualKey(&virtual_key);
1152 if (FAILED(hr))
1153 return hr;
1154 winui::Core::CorePhysicalKeyStatus status;
1155 hr = args->get_KeyStatus(&status);
1156 if (FAILED(hr))
1157 return hr;
1159 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
1160 status.RepeatCount,
1161 status.ScanCode,
1162 GetKeyboardEventFlags()));
1163 return S_OK;
1166 HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown(
1167 winui::Core::ICoreDispatcher* sender,
1168 winui::Core::IAcceleratorKeyEventArgs* args) {
1169 winsys::VirtualKey virtual_key;
1170 HRESULT hr = args->get_VirtualKey(&virtual_key);
1171 if (FAILED(hr))
1172 return hr;
1173 winui::Core::CorePhysicalKeyStatus status;
1174 hr = args->get_KeyStatus(&status);
1175 if (FAILED(hr))
1176 return hr;
1178 winui::Core::CoreAcceleratorKeyEventType event_type;
1179 hr = args->get_EventType(&event_type);
1180 if (FAILED(hr))
1181 return hr;
1183 uint32 keyboard_flags = GetKeyboardEventFlags();
1185 switch (event_type) {
1186 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter:
1187 ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key,
1188 status.RepeatCount,
1189 status.ScanCode,
1190 keyboard_flags));
1191 break;
1193 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown:
1194 // Don't send the Alt + F4 combination to Chrome as this is intended to
1195 // shut the metro environment down. Reason we check for Control here is
1196 // Windows does not shutdown metro if Ctrl is pressed along with Alt F4.
1197 // Other key combinations with Alt F4 shutdown metro.
1198 if ((virtual_key == VK_F4) && ((keyboard_flags & ui::EF_ALT_DOWN) &&
1199 !(keyboard_flags & ui::EF_CONTROL_DOWN)))
1200 return S_OK;
1201 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
1202 status.RepeatCount,
1203 status.ScanCode,
1204 keyboard_flags));
1205 break;
1207 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp:
1208 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
1209 status.RepeatCount,
1210 status.ScanCode,
1211 keyboard_flags));
1212 break;
1214 default:
1215 break;
1217 return S_OK;
1220 HRESULT ChromeAppViewAsh::OnCharacterReceived(
1221 winui::Core::ICoreWindow* sender,
1222 winui::Core::ICharacterReceivedEventArgs* args) {
1223 unsigned int char_code = 0;
1224 HRESULT hr = args->get_KeyCode(&char_code);
1225 if (FAILED(hr))
1226 return hr;
1228 winui::Core::CorePhysicalKeyStatus status;
1229 hr = args->get_KeyStatus(&status);
1230 if (FAILED(hr))
1231 return hr;
1233 ui_channel_->Send(new MetroViewerHostMsg_Character(char_code,
1234 status.RepeatCount,
1235 status.ScanCode,
1236 GetKeyboardEventFlags()));
1237 return S_OK;
1240 HRESULT ChromeAppViewAsh::OnWindowActivated(
1241 winui::Core::ICoreWindow* sender,
1242 winui::Core::IWindowActivatedEventArgs* args) {
1243 winui::Core::CoreWindowActivationState state;
1244 HRESULT hr = args->get_WindowActivationState(&state);
1245 if (FAILED(hr))
1246 return hr;
1248 // Treat both full activation (Ash was reopened from the Start Screen or from
1249 // any other Metro entry point in Windows) and pointer activation (user
1250 // clicked back in Ash after using another app on another monitor) the same.
1251 if (state == winui::Core::CoreWindowActivationState_CodeActivated ||
1252 state == winui::Core::CoreWindowActivationState_PointerActivated) {
1253 if (text_service_)
1254 text_service_->OnWindowActivated();
1255 ui_channel_->Send(new MetroViewerHostMsg_WindowActivated());
1257 return S_OK;
1260 HRESULT ChromeAppViewAsh::HandleSearchRequest(
1261 winapp::Activation::IActivatedEventArgs* args) {
1262 mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args;
1263 CheckHR(args->QueryInterface(
1264 winapp::Activation::IID_ISearchActivatedEventArgs, &search_args));
1266 if (!ui_channel_) {
1267 DVLOG(1) << "Launched to handle search request";
1268 LaunchChromeBrowserProcess(L"--windows8-search", args);
1271 mswrw::HString search_string;
1272 CheckHR(search_args->get_QueryText(search_string.GetAddressOf()));
1273 base::string16 search_text(MakeStdWString(search_string.Get()));
1275 ui_loop_.PostTask(FROM_HERE,
1276 base::Bind(&ChromeAppViewAsh::OnSearchRequest,
1277 base::Unretained(this),
1278 search_text));
1279 return S_OK;
1282 HRESULT ChromeAppViewAsh::HandleProtocolRequest(
1283 winapp::Activation::IActivatedEventArgs* args) {
1284 DVLOG(1) << __FUNCTION__;
1285 if (!ui_channel_)
1286 DVLOG(1) << "Launched to handle url request";
1288 mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs>
1289 protocol_args;
1290 CheckHR(args->QueryInterface(
1291 winapp::Activation::IID_IProtocolActivatedEventArgs,
1292 &protocol_args));
1294 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
1295 protocol_args->get_Uri(&uri);
1296 mswrw::HString url;
1297 uri->get_AbsoluteUri(url.GetAddressOf());
1298 base::string16 actual_url(MakeStdWString(url.Get()));
1299 DVLOG(1) << "Received url request: " << actual_url;
1301 ui_loop_.PostTask(FROM_HERE,
1302 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl,
1303 base::Unretained(this),
1304 actual_url));
1305 return S_OK;
1308 HRESULT ChromeAppViewAsh::OnEdgeGestureCompleted(
1309 winui::Input::IEdgeGesture* gesture,
1310 winui::Input::IEdgeGestureEventArgs* args) {
1311 ui_channel_->Send(new MetroViewerHostMsg_EdgeGesture());
1312 return S_OK;
1315 void ChromeAppViewAsh::OnSearchRequest(const base::string16& search_string) {
1316 DCHECK(ui_channel_);
1317 ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string));
1320 void ChromeAppViewAsh::OnNavigateToUrl(const base::string16& url) {
1321 DCHECK(ui_channel_);
1322 ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url));
1325 HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender,
1326 winui::Core::IWindowSizeChangedEventArgs* args) {
1327 if (!window_) {
1328 return S_OK;
1331 // winui::Core::IWindowSizeChangedEventArgs args->Size appears to return
1332 // scaled values under HiDPI. We will instead use GetWindowRect() which
1333 // should always return values in Pixels.
1334 RECT rect = {0};
1335 ::GetWindowRect(core_window_hwnd_, &rect);
1337 uint32 cx = static_cast<uint32>(rect.right - rect.left);
1338 uint32 cy = static_cast<uint32>(rect.bottom - rect.top);
1340 DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy;
1341 ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy));
1342 return S_OK;
1345 ///////////////////////////////////////////////////////////////////////////////
1347 ChromeAppViewFactory::ChromeAppViewFactory(
1348 winapp::Core::ICoreApplication* icore_app) {
1349 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
1350 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
1351 CheckHR(core_app.As(&app_exit));
1352 globals.app_exit = app_exit.Detach();
1355 IFACEMETHODIMP
1356 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
1357 *view = mswr::Make<ChromeAppViewAsh>().Detach();
1358 return (*view) ? S_OK : E_OUTOFMEMORY;