OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "win8/metro_driver/stdafx.h" | 5 #include "win8/metro_driver/stdafx.h" |
6 #include "win8/metro_driver/chrome_app_view_ash.h" | 6 #include "win8/metro_driver/chrome_app_view_ash.h" |
7 | 7 |
8 #include <corewindow.h> | 8 #include <corewindow.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 #include <windows.foundation.h> | 10 #include <windows.foundation.h> |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 | 61 |
62 // Global information used across the metro driver. | 62 // Global information used across the metro driver. |
63 struct Globals { | 63 struct Globals { |
64 winapp::Activation::ApplicationExecutionState previous_state; | 64 winapp::Activation::ApplicationExecutionState previous_state; |
65 winapp::Core::ICoreApplicationExit* app_exit; | 65 winapp::Core::ICoreApplicationExit* app_exit; |
66 BreakpadExceptionHandler breakpad_exception_handler; | 66 BreakpadExceptionHandler breakpad_exception_handler; |
67 } globals; | 67 } globals; |
68 | 68 |
69 namespace { | 69 namespace { |
70 | 70 |
71 // TODO(robertshield): Share this with chrome_app_view.cc | 71 enum KeyModifier { |
72 void MetroExit() { | 72 NONE, |
73 globals.app_exit->Exit(); | 73 SHIFT = 1, |
| 74 CONTROL = 2, |
| 75 ALT = 4 |
| 76 }; |
| 77 |
| 78 // Helper function to send keystrokes via the SendInput function. |
| 79 // mnemonic_char: The keystroke to be sent. |
| 80 // modifiers: Combination with Alt, Ctrl, Shift, etc. |
| 81 void SendMnemonic( |
| 82 WORD mnemonic_char, KeyModifier modifiers) { |
| 83 INPUT keys[4] = {0}; // Keyboard events |
| 84 int key_count = 0; // Number of generated events |
| 85 |
| 86 if (modifiers & SHIFT) { |
| 87 keys[key_count].type = INPUT_KEYBOARD; |
| 88 keys[key_count].ki.wVk = VK_SHIFT; |
| 89 keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0); |
| 90 key_count++; |
| 91 } |
| 92 |
| 93 if (modifiers & CONTROL) { |
| 94 keys[key_count].type = INPUT_KEYBOARD; |
| 95 keys[key_count].ki.wVk = VK_CONTROL; |
| 96 keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0); |
| 97 key_count++; |
| 98 } |
| 99 |
| 100 if (modifiers & ALT) { |
| 101 keys[key_count].type = INPUT_KEYBOARD; |
| 102 keys[key_count].ki.wVk = VK_MENU; |
| 103 keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0); |
| 104 key_count++; |
| 105 } |
| 106 |
| 107 keys[key_count].type = INPUT_KEYBOARD; |
| 108 keys[key_count].ki.wVk = mnemonic_char; |
| 109 keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0); |
| 110 key_count++; |
| 111 |
| 112 bool should_sleep = key_count > 1; |
| 113 |
| 114 // Send key downs. |
| 115 for (int i = 0; i < key_count; i++) { |
| 116 SendInput(1, &keys[ i ], sizeof(keys[0])); |
| 117 keys[i].ki.dwFlags |= KEYEVENTF_KEYUP; |
| 118 if (should_sleep) |
| 119 Sleep(10); |
| 120 } |
| 121 |
| 122 // Now send key ups in reverse order. |
| 123 for (int i = key_count; i; i--) { |
| 124 SendInput(1, &keys[ i - 1 ], sizeof(keys[0])); |
| 125 if (should_sleep) |
| 126 Sleep(10); |
| 127 } |
| 128 } |
| 129 |
| 130 // Helper function to Exit metro chrome cleanly. If we are in the foreground |
| 131 // then we try and exit by sending an Alt+F4 key combination to the core |
| 132 // window which ensures that the chrome application tile does not show up in |
| 133 // the running metro apps list on the top left corner. |
| 134 void MetroExit(HWND core_window) { |
| 135 if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) { |
| 136 DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; |
| 137 SendMnemonic(VK_F4, ALT); |
| 138 } else { |
| 139 globals.app_exit->Exit(); |
| 140 } |
74 } | 141 } |
75 | 142 |
76 class ChromeChannelListener : public IPC::Listener { | 143 class ChromeChannelListener : public IPC::Listener { |
77 public: | 144 public: |
78 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view) | 145 ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view) |
79 : ui_proxy_(ui_loop->message_loop_proxy()), | 146 : ui_proxy_(ui_loop->message_loop_proxy()), |
80 app_view_(app_view) {} | 147 app_view_(app_view) {} |
81 | 148 |
82 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { | 149 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
83 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message) | 150 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener, message) |
84 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop, | 151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop, |
85 OnActivateDesktop) | 152 OnActivateDesktop) |
86 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop, | 153 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop, |
87 OnOpenURLOnDesktop) | 154 OnOpenURLOnDesktop) |
88 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor) | 155 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor, OnSetCursor) |
89 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen, | 156 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen, |
90 OnDisplayFileOpenDialog) | 157 OnDisplayFileOpenDialog) |
91 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs, | 158 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs, |
92 OnDisplayFileSaveAsDialog) | 159 OnDisplayFileSaveAsDialog) |
93 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder, | 160 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder, |
94 OnDisplayFolderPicker) | 161 OnDisplayFolderPicker) |
95 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos) | 162 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos, OnSetCursorPos) |
96 IPC_MESSAGE_UNHANDLED(__debugbreak()) | 163 IPC_MESSAGE_UNHANDLED(__debugbreak()) |
97 IPC_END_MESSAGE_MAP() | 164 IPC_END_MESSAGE_MAP() |
98 return true; | 165 return true; |
99 } | 166 } |
100 | 167 |
101 virtual void OnChannelError() OVERRIDE { | 168 virtual void OnChannelError() OVERRIDE { |
102 DVLOG(1) << "Channel error"; | 169 DVLOG(1) << "Channel error. Exiting."; |
103 MetroExit(); | 170 MetroExit(app_view_->core_window()); |
| 171 // In early Windows 8 versions the code above sometimes fails so we call |
| 172 // it a second time with a NULL window which just calls Exit(). |
| 173 ui_proxy_->PostDelayedTask(FROM_HERE, |
| 174 base::Bind(&MetroExit, HWND(NULL)), |
| 175 base::TimeDelta::FromMilliseconds(100)); |
104 } | 176 } |
105 | 177 |
106 private: | 178 private: |
107 void OnActivateDesktop(const base::FilePath& shortcut) { | 179 void OnActivateDesktop(const base::FilePath& shortcut) { |
108 ui_proxy_->PostTask(FROM_HERE, | 180 ui_proxy_->PostTask(FROM_HERE, |
109 base::Bind(&ChromeAppViewAsh::OnActivateDesktop, | 181 base::Bind(&ChromeAppViewAsh::OnActivateDesktop, |
110 base::Unretained(app_view_), | 182 base::Unretained(app_view_), |
111 shortcut)); | 183 shortcut)); |
112 } | 184 } |
113 | 185 |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; | 626 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr; |
555 if (SUCCEEDED(hr)) | 627 if (SUCCEEDED(hr)) |
556 hr = E_UNEXPECTED; | 628 hr = E_UNEXPECTED; |
557 } | 629 } |
558 } | 630 } |
559 return hr; | 631 return hr; |
560 } | 632 } |
561 | 633 |
562 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) { | 634 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) { |
563 DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n"; | 635 DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n"; |
| 636 |
| 637 // As we are the top level window, the exiting is done async so we manage |
| 638 // to execute the entire function including the final Send(). |
| 639 MetroExit(core_window()); |
| 640 |
564 // We are just executing delegate_execute here without parameters. Assumption | 641 // We are just executing delegate_execute here without parameters. Assumption |
565 // here is that this process will be reused by shell when asking for | 642 // here is that this process will be reused by shell when asking for |
566 // IExecuteCommand interface. | 643 // IExecuteCommand interface. |
567 | 644 |
568 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE | 645 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE |
569 // and place it metro.h or similar accessible file from all code code paths | 646 // and place it metro.h or similar accessible file from all code code paths |
570 // using this function. | 647 // using this function. |
571 SHELLEXECUTEINFO sei = { sizeof(sei) }; | 648 SHELLEXECUTEINFO sei = { sizeof(sei) }; |
572 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; | 649 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; |
573 sei.nShow = SW_SHOWNORMAL; | 650 sei.nShow = SW_SHOWNORMAL; |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1028 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; | 1105 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit; |
1029 CheckHR(core_app.As(&app_exit)); | 1106 CheckHR(core_app.As(&app_exit)); |
1030 globals.app_exit = app_exit.Detach(); | 1107 globals.app_exit = app_exit.Detach(); |
1031 } | 1108 } |
1032 | 1109 |
1033 IFACEMETHODIMP | 1110 IFACEMETHODIMP |
1034 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { | 1111 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) { |
1035 *view = mswr::Make<ChromeAppViewAsh>().Detach(); | 1112 *view = mswr::Make<ChromeAppViewAsh>().Detach(); |
1036 return (*view) ? S_OK : E_OUTOFMEMORY; | 1113 return (*view) ? S_OK : E_OUTOFMEMORY; |
1037 } | 1114 } |
OLD | NEW |