Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: win8/metro_driver/chrome_app_view_ash.cc

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

Powered by Google App Engine
This is Rietveld 408576698