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>
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 "chrome/common/chrome_switches.h"
21 #include "ipc/ipc_channel.h"
22 #include "ipc/ipc_channel_proxy.h"
23 #include "ipc/ipc_sender.h"
24 #include "ui/events/gestures/gesture_sequence.h"
25 #include "ui/metro_viewer/metro_viewer_messages.h"
26 #include "win8/metro_driver/file_picker_ash.h"
27 #include "win8/metro_driver/metro_driver.h"
28 #include "win8/metro_driver/winrt_utils.h"
29 #include "win8/viewer/metro_viewer_constants.h"
31 typedef winfoundtn::ITypedEventHandler<
32 winapp::Core::CoreApplicationView*,
33 winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
35 typedef winfoundtn::ITypedEventHandler<
36 winui::Core::CoreWindow*,
37 winui::Core::PointerEventArgs*> PointerEventHandler;
39 typedef winfoundtn::ITypedEventHandler<
40 winui::Core::CoreWindow*,
41 winui::Core::KeyEventArgs*> KeyEventHandler;
43 typedef winfoundtn::ITypedEventHandler<
44 winui::Core::CoreDispatcher*,
45 winui::Core::AcceleratorKeyEventArgs*> AcceleratorKeyEventHandler;
47 typedef winfoundtn::ITypedEventHandler<
48 winui::Core::CoreWindow*,
49 winui::Core::CharacterReceivedEventArgs*> CharEventHandler;
51 typedef winfoundtn::ITypedEventHandler<
52 winui::Core::CoreWindow*,
53 winui::Core::WindowActivatedEventArgs*> WindowActivatedHandler;
55 typedef winfoundtn::ITypedEventHandler<
56 winui::Core::CoreWindow*,
57 winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
59 // This function is exported by chrome.exe.
60 typedef int (__cdecl *BreakpadExceptionHandler)(EXCEPTION_POINTERS* info);
62 // Global information used across the metro driver.
64 winapp::Activation::ApplicationExecutionState previous_state;
65 winapp::Core::ICoreApplicationExit* app_exit;
66 BreakpadExceptionHandler breakpad_exception_handler;
71 // TODO(robertshield): Share this with chrome_app_view.cc
73 globals.app_exit->Exit();
76 class ChromeChannelListener : public IPC::Listener {
78 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
79 : ui_proxy_(ui_loop->message_loop_proxy()),
80 app_view_(app_view) {}
82 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
83 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message)
84 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop,
86 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop,
88 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor)
89 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen,
90 OnDisplayFileOpenDialog)
91 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs,
92 OnDisplayFileSaveAsDialog)
93 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder,
94 OnDisplayFolderPicker)
95 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos)
96 IPC_MESSAGE_UNHANDLED(__debugbreak())
101 virtual void OnChannelError() OVERRIDE {
102 DVLOG(1) << "Channel error";
107 void OnActivateDesktop(const base::FilePath& shortcut) {
108 ui_proxy_->PostTask(FROM_HERE,
109 base::Bind(&ChromeAppViewAsh::OnActivateDesktop,
110 base::Unretained(app_view_),
114 void OnOpenURLOnDesktop(const base::FilePath& shortcut,
115 const string16& url) {
116 ui_proxy_->PostTask(FROM_HERE,
117 base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop,
118 base::Unretained(app_view_),
122 void OnSetCursor(int64 cursor) {
123 ui_proxy_->PostTask(FROM_HERE,
124 base::Bind(&ChromeAppViewAsh::OnSetCursor,
125 base::Unretained(app_view_),
126 reinterpret_cast<HCURSOR>(cursor)));
129 void OnDisplayFileOpenDialog(const string16& title,
130 const string16& filter,
131 const base::FilePath& default_path,
132 bool allow_multiple_files) {
133 ui_proxy_->PostTask(FROM_HERE,
134 base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog,
135 base::Unretained(app_view_),
139 allow_multiple_files));
142 void OnDisplayFileSaveAsDialog(
143 const MetroViewerHostMsg_SaveAsDialogParams& params) {
146 base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog,
147 base::Unretained(app_view_),
151 void OnDisplayFolderPicker(const string16& title) {
154 base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker,
155 base::Unretained(app_view_),
159 void OnSetCursorPos(int x, int y) {
160 VLOG(1) << "In IPC OnSetCursorPos: " << x << ", " << y;
163 base::Bind(&ChromeAppViewAsh::OnSetCursorPos,
164 base::Unretained(app_view_),
169 scoped_refptr<base::MessageLoopProxy> ui_proxy_;
170 ChromeAppViewAsh* app_view_;
173 bool WaitForChromeIPCConnection(const std::string& channel_name) {
175 while (!IPC::Channel::IsNamedServerInitialized(channel_name) &&
176 ms_elapsed < 10000) {
180 return IPC::Channel::IsNamedServerInitialized(channel_name);
183 // This class helps decoding the pointer properties of an event.
184 class PointerInfoHandler {
190 update_kind_(winui::Input::PointerUpdateKind_Other),
194 HRESULT Init(winui::Core::IPointerEventArgs* args) {
195 HRESULT hr = args->get_CurrentPoint(&pointer_point_);
199 winfoundtn::Point point;
200 hr = pointer_point_->get_Position(&point);
204 mswr::ComPtr<winui::Input::IPointerPointProperties> properties;
205 hr = pointer_point_->get_Properties(&properties);
209 hr = properties->get_PointerUpdateKind(&update_kind_);
213 hr = properties->get_MouseWheelDelta(&wheel_delta_);
218 pointer_point_->get_Timestamp(×tamp_);
219 pointer_point_->get_PointerId(&pointer_id_);
220 // Map the OS touch event id to a range allowed by the gesture recognizer.
222 pointer_id_ %= ui::GestureSequence::kMaxGesturePoints;
226 bool IsType(windevs::Input::PointerDeviceType type) const {
227 mswr::ComPtr<windevs::Input::IPointerDevice> pointer_device;
228 CheckHR(pointer_point_->get_PointerDevice(&pointer_device));
229 windevs::Input::PointerDeviceType device_type;
230 CheckHR(pointer_device->get_PointerDeviceType(&device_type));
231 return (device_type == type);
234 bool IsMouse() const {
235 return IsType(windevs::Input::PointerDeviceType_Mouse);
238 bool IsTouch() const {
239 return IsType(windevs::Input::PointerDeviceType_Touch);
242 int32 wheel_delta() const {
246 ui::EventFlags flags() {
247 switch (update_kind_) {
248 case winui::Input::PointerUpdateKind_LeftButtonPressed:
249 return ui::EF_LEFT_MOUSE_BUTTON;
250 case winui::Input::PointerUpdateKind_LeftButtonReleased:
251 return ui::EF_LEFT_MOUSE_BUTTON;
252 case winui::Input::PointerUpdateKind_RightButtonPressed:
253 return ui::EF_RIGHT_MOUSE_BUTTON;
254 case winui::Input::PointerUpdateKind_RightButtonReleased:
255 return ui::EF_RIGHT_MOUSE_BUTTON;
256 case winui::Input::PointerUpdateKind_MiddleButtonPressed:
257 return ui::EF_MIDDLE_MOUSE_BUTTON;
258 case winui::Input::PointerUpdateKind_MiddleButtonReleased:
259 return ui::EF_MIDDLE_MOUSE_BUTTON;
265 int x() const { return x_; }
266 int y() const { return y_; }
268 uint32 pointer_id() const {
272 uint64 timestamp() const { return timestamp_; }
279 winui::Input::PointerUpdateKind update_kind_;
280 mswr::ComPtr<winui::Input::IPointerPoint> pointer_point_;
284 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
285 // We're entering a nested message loop, let's allow dispatching
286 // tasks while we're in there.
287 base::MessageLoop::current()->SetNestableTasksAllowed(true);
289 // Enter main core message loop. There are several ways to exit it
291 // 1 - User action like ALT-F4.
292 // 2 - Calling ICoreApplicationExit::Exit().
293 // 3- Posting WM_CLOSE to the core window.
294 HRESULT hr = dispatcher->ProcessEvents(
295 winui::Core::CoreProcessEventsOption
296 ::CoreProcessEventsOption_ProcessUntilQuit);
298 // Wind down the thread's chrome message loop.
299 base::MessageLoop::current()->Quit();
302 // Helper to return the state of the shift/control/alt keys.
303 uint32 GetKeyboardEventFlags() {
305 if (base::win::IsShiftPressed())
306 flags |= ui::EF_SHIFT_DOWN;
307 if (base::win::IsCtrlPressed())
308 flags |= ui::EF_CONTROL_DOWN;
309 if (base::win::IsAltPressed())
310 flags |= ui::EF_ALT_DOWN;
314 bool LaunchChromeBrowserProcess (const wchar_t* additional_parameters) {
315 DVLOG(1) << "Launching chrome server";
316 base::FilePath chrome_exe_path;
318 if (!PathService::Get(base::FILE_EXE, &chrome_exe_path))
321 string16 parameters = L"--silent-launch --viewer-connect ";
322 if (additional_parameters)
323 parameters += additional_parameters;
325 SHELLEXECUTEINFO sei = { sizeof(sei) };
326 sei.nShow = SW_SHOWNORMAL;
327 sei.lpFile = chrome_exe_path.value().c_str();
328 sei.lpDirectory = L"";
329 sei.lpParameters = parameters.c_str();
330 ::ShellExecuteEx(&sei);
336 ChromeAppViewAsh::ChromeAppViewAsh()
337 : mouse_down_flags_(ui::EF_NONE),
338 ui_channel_(nullptr),
339 core_window_hwnd_(NULL),
340 ui_loop_(base::MessageLoop::TYPE_UI) {
341 DVLOG(1) << __FUNCTION__;
342 globals.previous_state =
343 winapp::Activation::ApplicationExecutionState_NotRunning;
346 ChromeAppViewAsh::~ChromeAppViewAsh() {
347 DVLOG(1) << __FUNCTION__;
351 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView* view) {
353 DVLOG(1) << __FUNCTION__;
354 HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
355 this, &ChromeAppViewAsh::OnActivate).Get(),
362 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow* window) {
364 DVLOG(1) << __FUNCTION__;
366 // Retrieve the native window handle via the interop layer.
367 mswr::ComPtr<ICoreWindowInterop> interop;
368 HRESULT hr = window->QueryInterface(interop.GetAddressOf());
370 hr = interop->get_WindowHandle(&core_window_hwnd_);
373 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
374 this, &ChromeAppViewAsh::OnSizeChanged).Get(),
378 // Register for pointer and keyboard notifications. We forward
379 // them to the browser process via IPC.
380 hr = window_->add_PointerMoved(mswr::Callback<PointerEventHandler>(
381 this, &ChromeAppViewAsh::OnPointerMoved).Get(),
382 &pointermoved_token_);
385 hr = window_->add_PointerPressed(mswr::Callback<PointerEventHandler>(
386 this, &ChromeAppViewAsh::OnPointerPressed).Get(),
387 &pointerpressed_token_);
390 hr = window_->add_PointerReleased(mswr::Callback<PointerEventHandler>(
391 this, &ChromeAppViewAsh::OnPointerReleased).Get(),
392 &pointerreleased_token_);
395 hr = window_->add_KeyDown(mswr::Callback<KeyEventHandler>(
396 this, &ChromeAppViewAsh::OnKeyDown).Get(),
400 hr = window_->add_KeyUp(mswr::Callback<KeyEventHandler>(
401 this, &ChromeAppViewAsh::OnKeyUp).Get(),
405 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
406 hr = window_->get_Dispatcher(&dispatcher);
407 CheckHR(hr, "Get Dispatcher failed.");
409 mswr::ComPtr<winui::Core::ICoreAcceleratorKeys> accelerator_keys;
410 hr = dispatcher.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys),
411 reinterpret_cast<void**>(
412 accelerator_keys.GetAddressOf()));
413 CheckHR(hr, "QI for ICoreAcceleratorKeys failed.");
414 hr = accelerator_keys->add_AcceleratorKeyActivated(
415 mswr::Callback<AcceleratorKeyEventHandler>(
416 this, &ChromeAppViewAsh::OnAcceleratorKeyDown).Get(),
417 &accel_keydown_token_);
420 hr = window_->add_PointerWheelChanged(mswr::Callback<PointerEventHandler>(
421 this, &ChromeAppViewAsh::OnWheel).Get(),
425 hr = window_->add_CharacterReceived(mswr::Callback<CharEventHandler>(
426 this, &ChromeAppViewAsh::OnCharacterReceived).Get(),
427 &character_received_token_);
430 hr = window_->add_Activated(mswr::Callback<WindowActivatedHandler>(
431 this, &ChromeAppViewAsh::OnWindowActivated).Get(),
432 &window_activated_token_);
435 // By initializing the direct 3D swap chain with the corewindow
436 // we can now directly blit to it from the browser process.
437 direct3d_helper_.Initialize(window);
438 DVLOG(1) << "Initialized Direct3D.";
443 ChromeAppViewAsh::Load(HSTRING entryPoint) {
444 DVLOG(1) << __FUNCTION__;
449 ChromeAppViewAsh::Run() {
450 DVLOG(1) << __FUNCTION__;
451 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
452 HRESULT hr = window_->get_Dispatcher(&dispatcher);
453 CheckHR(hr, "Dispatcher failed.");
455 hr = window_->Activate();
457 DLOG(WARNING) << "activation failed hr=" << hr;
461 // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
462 base::Thread io_thread("metro_IO_thread");
463 base::Thread::Options options;
464 options.message_loop_type = base::MessageLoop::TYPE_IO;
465 io_thread.StartWithOptions(options);
467 // Start up Chrome and wait for the desired IPC server connection to exist.
468 WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName);
470 // In Aura mode we create an IPC channel to the browser, then ask it to
472 ChromeChannelListener ui_channel_listener(&ui_loop_, this);
473 IPC::ChannelProxy ui_channel(win8::kMetroViewerIPCChannelName,
474 IPC::Channel::MODE_NAMED_CLIENT,
475 &ui_channel_listener,
476 io_thread.message_loop_proxy());
477 ui_channel_ = &ui_channel;
479 // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
480 // browser will use D3D from the browser process to present to our Window.
481 ui_channel_->Send(new MetroViewerHostMsg_SetTargetSurface(
482 gfx::NativeViewId(core_window_hwnd_)));
483 DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_;
485 // Send an initial size message so that the Ash root window host gets sized
488 ::GetWindowRect(core_window_hwnd_, &rect);
490 new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left,
491 rect.bottom - rect.top));
493 // And post the task that'll do the inner Metro message pumping to it.
494 ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
497 DVLOG(0) << "ProcessEvents done, hr=" << hr;
502 ChromeAppViewAsh::Uninitialize() {
503 DVLOG(1) << __FUNCTION__;
506 core_window_hwnd_ = NULL;
511 HRESULT ChromeAppViewAsh::Unsnap() {
512 mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
513 HRESULT hr = winrt_utils::CreateActivationFactory(
514 RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
515 view_statics.GetAddressOf());
518 winui::ViewManagement::ApplicationViewState state =
519 winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
520 hr = view_statics->get_Value(&state);
523 if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
524 boolean success = FALSE;
525 hr = view_statics->TryUnsnap(&success);
527 if (FAILED(hr) || !success) {
528 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
536 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) {
537 DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n";
538 // We are just executing delegate_execute here without parameters. Assumption
539 // here is that this process will be reused by shell when asking for
540 // IExecuteCommand interface.
542 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
543 // and place it metro.h or similar accessible file from all code code paths
544 // using this function.
545 SHELLEXECUTEINFO sei = { sizeof(sei) };
546 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
547 sei.nShow = SW_SHOWNORMAL;
548 sei.lpFile = file_path.value().c_str();
549 sei.lpParameters = NULL;
550 ::ShellExecuteExW(&sei);
551 ui_channel_->Send(new MetroViewerHostMsg_ActivateDesktopDone());
554 void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath& shortcut,
555 const string16& url) {
556 base::FilePath::StringType file = shortcut.value();
557 SHELLEXECUTEINFO sei = { sizeof(sei) };
558 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
559 sei.nShow = SW_SHOWNORMAL;
560 sei.lpFile = file.c_str();
561 sei.lpDirectory = L"";
562 sei.lpParameters = url.c_str();
563 BOOL result = ShellExecuteEx(&sei);
566 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor) {
567 ::SetCursor(HCURSOR(cursor));
570 void ChromeAppViewAsh::OnDisplayFileOpenDialog(
571 const string16& title,
572 const string16& filter,
573 const base::FilePath& default_path,
574 bool allow_multiple_files) {
575 DVLOG(1) << __FUNCTION__;
577 // The OpenFilePickerSession instance is deleted when we receive a
578 // callback from the OpenFilePickerSession class about the completion of the
580 FilePickerSessionBase* file_picker_ =
581 new OpenFilePickerSession(this,
585 allow_multiple_files);
589 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
590 const MetroViewerHostMsg_SaveAsDialogParams& params) {
591 DVLOG(1) << __FUNCTION__;
593 // The SaveFilePickerSession instance is deleted when we receive a
594 // callback from the SaveFilePickerSession class about the completion of the
596 FilePickerSessionBase* file_picker_ =
597 new SaveFilePickerSession(this, params);
601 void ChromeAppViewAsh::OnDisplayFolderPicker(const string16& title) {
602 DVLOG(1) << __FUNCTION__;
603 // The FolderPickerSession instance is deleted when we receive a
604 // callback from the FolderPickerSession class about the completion of the
606 FilePickerSessionBase* file_picker_ = new FolderPickerSession(this, title);
610 void ChromeAppViewAsh::OnSetCursorPos(int x, int y) {
612 ::SetCursorPos(x, y);
613 DVLOG(1) << "In UI OnSetCursorPos: " << x << ", " << y;
614 ui_channel_->Send(new MetroViewerHostMsg_SetCursorPosAck());
615 // Generate a fake mouse move which matches the SetCursor coordinates as
616 // the browser expects to receive a mouse move for these coordinates.
617 // It is not clear why we don't receive a real mouse move in response to
618 // the SetCursorPos calll above.
619 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(x, y, 0));
623 void ChromeAppViewAsh::OnOpenFileCompleted(
624 OpenFilePickerSession* open_file_picker,
626 DVLOG(1) << __FUNCTION__;
627 DVLOG(1) << "Success: " << success;
629 if (open_file_picker->allow_multi_select()) {
630 ui_channel_->Send(new MetroViewerHostMsg_MultiFileOpenDone(
631 success, open_file_picker->filenames()));
633 ui_channel_->Send(new MetroViewerHostMsg_FileOpenDone(
634 success, base::FilePath(open_file_picker->result())));
637 delete open_file_picker;
640 void ChromeAppViewAsh::OnSaveFileCompleted(
641 SaveFilePickerSession* save_file_picker,
643 DVLOG(1) << __FUNCTION__;
644 DVLOG(1) << "Success: " << success;
646 ui_channel_->Send(new MetroViewerHostMsg_FileSaveAsDone(
648 base::FilePath(save_file_picker->result()),
649 save_file_picker->filter_index()));
651 delete save_file_picker;
654 void ChromeAppViewAsh::OnFolderPickerCompleted(
655 FolderPickerSession* folder_picker,
657 DVLOG(1) << __FUNCTION__;
658 DVLOG(1) << "Success: " << success;
660 ui_channel_->Send(new MetroViewerHostMsg_SelectFolderDone(
662 base::FilePath(folder_picker->result())));
664 delete folder_picker;
667 HRESULT ChromeAppViewAsh::OnActivate(
668 winapp::Core::ICoreApplicationView*,
669 winapp::Activation::IActivatedEventArgs* args) {
670 DVLOG(1) << __FUNCTION__;
671 // Note: If doing more work in this function, you migth need to call
672 // get_PreviousExecutionState() and skip the work if the result is
673 // ApplicationExecutionState_Running and globals.previous_state is too.
674 args->get_PreviousExecutionState(&globals.previous_state);
675 DVLOG(1) << "Previous Execution State: " << globals.previous_state;
677 winapp::Activation::ActivationKind activation_kind;
678 CheckHR(args->get_Kind(&activation_kind));
679 DVLOG(1) << "Activation kind: " << activation_kind;
681 if (activation_kind == winapp::Activation::ActivationKind_Search)
682 HandleSearchRequest(args);
683 else if (activation_kind == winapp::Activation::ActivationKind_Protocol)
684 HandleProtocolRequest(args);
686 LaunchChromeBrowserProcess(NULL);
687 // We call ICoreWindow::Activate after the handling for the search/protocol
688 // requests because Chrome can be launched to handle a search request which
689 // in turn launches the chrome browser process in desktop mode via
690 // ShellExecute. If we call ICoreWindow::Activate before this, then
691 // Windows kills the metro chrome process when it calls ShellExecute. Seems
697 HRESULT ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow* sender,
698 winui::Core::IPointerEventArgs* args) {
699 PointerInfoHandler pointer;
700 HRESULT hr = pointer.Init(args);
704 if (pointer.IsMouse()) {
705 ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(
708 mouse_down_flags_ | GetKeyboardEventFlags()));
710 DCHECK(pointer.IsTouch());
711 ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(),
714 pointer.pointer_id()));
719 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed
720 // event for the first button pressed and the last button released in a sequence
722 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
723 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events.
724 HRESULT ChromeAppViewAsh::OnPointerPressed(
725 winui::Core::ICoreWindow* sender,
726 winui::Core::IPointerEventArgs* args) {
727 PointerInfoHandler pointer;
728 HRESULT hr = pointer.Init(args);
732 if (pointer.IsMouse()) {
733 // TODO: this is wrong, more than one pointer may be down at a time.
734 mouse_down_flags_ = pointer.flags();
735 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
739 ui::ET_MOUSE_PRESSED,
740 static_cast<ui::EventFlags>(
741 mouse_down_flags_ | GetKeyboardEventFlags())));
743 DCHECK(pointer.IsTouch());
744 ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(),
747 pointer.pointer_id()));
752 HRESULT ChromeAppViewAsh::OnPointerReleased(
753 winui::Core::ICoreWindow* sender,
754 winui::Core::IPointerEventArgs* args) {
755 PointerInfoHandler pointer;
756 HRESULT hr = pointer.Init(args);
760 if (pointer.IsMouse()) {
761 // TODO: this is wrong, more than one pointer may be down at a time.
762 mouse_down_flags_ = ui::EF_NONE;
763 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
767 ui::ET_MOUSE_RELEASED,
768 static_cast<ui::EventFlags>(
769 pointer.flags() | GetKeyboardEventFlags())));
771 DCHECK(pointer.IsTouch());
772 ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(),
775 pointer.pointer_id()));
780 HRESULT ChromeAppViewAsh::OnWheel(
781 winui::Core::ICoreWindow* sender,
782 winui::Core::IPointerEventArgs* args) {
783 PointerInfoHandler pointer;
784 HRESULT hr = pointer.Init(args);
787 DCHECK(pointer.IsMouse());
788 ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(), pointer.y(),
789 pointer.wheel_delta(),
795 HRESULT ChromeAppViewAsh::OnKeyDown(
796 winui::Core::ICoreWindow* sender,
797 winui::Core::IKeyEventArgs* args) {
798 winsys::VirtualKey virtual_key;
799 HRESULT hr = args->get_VirtualKey(&virtual_key);
802 winui::Core::CorePhysicalKeyStatus status;
803 hr = args->get_KeyStatus(&status);
807 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
810 GetKeyboardEventFlags()));
814 HRESULT ChromeAppViewAsh::OnKeyUp(
815 winui::Core::ICoreWindow* sender,
816 winui::Core::IKeyEventArgs* args) {
817 winsys::VirtualKey virtual_key;
818 HRESULT hr = args->get_VirtualKey(&virtual_key);
821 winui::Core::CorePhysicalKeyStatus status;
822 hr = args->get_KeyStatus(&status);
826 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
829 GetKeyboardEventFlags()));
833 HRESULT ChromeAppViewAsh::OnAcceleratorKeyDown(
834 winui::Core::ICoreDispatcher* sender,
835 winui::Core::IAcceleratorKeyEventArgs* args) {
836 winsys::VirtualKey virtual_key;
837 HRESULT hr = args->get_VirtualKey(&virtual_key);
840 winui::Core::CorePhysicalKeyStatus status;
841 hr = args->get_KeyStatus(&status);
845 winui::Core::CoreAcceleratorKeyEventType event_type;
846 hr = args->get_EventType(&event_type);
850 uint32 keyboard_flags = GetKeyboardEventFlags();
852 switch (event_type) {
853 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter:
854 ui_channel_->Send(new MetroViewerHostMsg_Character(virtual_key,
860 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown:
861 ui_channel_->Send(new MetroViewerHostMsg_KeyDown(virtual_key,
867 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp:
868 ui_channel_->Send(new MetroViewerHostMsg_KeyUp(virtual_key,
880 HRESULT ChromeAppViewAsh::OnCharacterReceived(
881 winui::Core::ICoreWindow* sender,
882 winui::Core::ICharacterReceivedEventArgs* args) {
883 unsigned int char_code = 0;
884 HRESULT hr = args->get_KeyCode(&char_code);
888 winui::Core::CorePhysicalKeyStatus status;
889 hr = args->get_KeyStatus(&status);
893 ui_channel_->Send(new MetroViewerHostMsg_Character(char_code,
896 GetKeyboardEventFlags()));
900 HRESULT ChromeAppViewAsh::OnWindowActivated(
901 winui::Core::ICoreWindow* sender,
902 winui::Core::IWindowActivatedEventArgs* args) {
903 winui::Core::CoreWindowActivationState state;
904 HRESULT hr = args->get_WindowActivationState(&state);
908 // Treat both full activation (Ash was reopened from the Start Screen or from
909 // any other Metro entry point in Windows) and pointer activation (user
910 // clicked back in Ash after using another app on another monitor) the same.
911 if (state == winui::Core::CoreWindowActivationState_CodeActivated ||
912 state == winui::Core::CoreWindowActivationState_PointerActivated) {
913 ui_channel_->Send(new MetroViewerHostMsg_WindowActivated());
918 HRESULT ChromeAppViewAsh::HandleSearchRequest(
919 winapp::Activation::IActivatedEventArgs* args) {
920 mswr::ComPtr<winapp::Activation::ISearchActivatedEventArgs> search_args;
921 CheckHR(args->QueryInterface(
922 winapp::Activation::IID_ISearchActivatedEventArgs, &search_args));
925 DVLOG(1) << "Launched to handle search request";
926 LaunchChromeBrowserProcess(L"--windows8-search");
929 mswrw::HString search_string;
930 CheckHR(search_args->get_QueryText(search_string.GetAddressOf()));
931 string16 search_text(MakeStdWString(search_string.Get()));
933 ui_loop_.PostTask(FROM_HERE,
934 base::Bind(&ChromeAppViewAsh::OnSearchRequest,
935 base::Unretained(this),
940 HRESULT ChromeAppViewAsh::HandleProtocolRequest(
941 winapp::Activation::IActivatedEventArgs* args) {
942 DVLOG(1) << __FUNCTION__;
944 DVLOG(1) << "Launched to handle url request";
946 mswr::ComPtr<winapp::Activation::IProtocolActivatedEventArgs>
948 CheckHR(args->QueryInterface(
949 winapp::Activation::IID_IProtocolActivatedEventArgs,
952 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
953 protocol_args->get_Uri(&uri);
955 uri->get_AbsoluteUri(url.GetAddressOf());
956 string16 actual_url(MakeStdWString(url.Get()));
957 DVLOG(1) << "Received url request: " << actual_url;
959 ui_loop_.PostTask(FROM_HERE,
960 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl,
961 base::Unretained(this),
966 void ChromeAppViewAsh::OnSearchRequest(const string16& search_string) {
968 ui_channel_->Send(new MetroViewerHostMsg_SearchRequest(search_string));
971 void ChromeAppViewAsh::OnNavigateToUrl(const string16& url) {
973 ui_channel_->Send(new MetroViewerHostMsg_OpenURL(url));
976 HRESULT ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow* sender,
977 winui::Core::IWindowSizeChangedEventArgs* args) {
982 winfoundtn::Size size;
983 HRESULT hr = args->get_Size(&size);
987 uint32 cx = static_cast<uint32>(size.Width);
988 uint32 cy = static_cast<uint32>(size.Height);
990 DVLOG(1) << "Window size changed: width=" << cx << ", height=" << cy;
991 ui_channel_->Send(new MetroViewerHostMsg_WindowSizeChanged(cx, cy));
995 ///////////////////////////////////////////////////////////////////////////////
997 ChromeAppViewFactory::ChromeAppViewFactory(
998 winapp::Core::ICoreApplication* icore_app,
999 LPTHREAD_START_ROUTINE host_main,
1000 void* host_context) {
1001 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
1002 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
1003 CheckHR(core_app.As(&app_exit));
1004 globals.app_exit = app_exit.Detach();
1008 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
1009 *view = mswr::Make<ChromeAppViewAsh>().Detach();
1010 return (*view) ? S_OK : E_OUTOFMEMORY;