| Index: win8/metro_driver/chrome_app_view_ash.cc
|
| ===================================================================
|
| --- win8/metro_driver/chrome_app_view_ash.cc (revision 234017)
|
| +++ win8/metro_driver/chrome_app_view_ash.cc (working copy)
|
| @@ -68,11 +68,78 @@
|
|
|
| namespace {
|
|
|
| -// TODO(robertshield): Share this with chrome_app_view.cc
|
| -void MetroExit() {
|
| - globals.app_exit->Exit();
|
| +enum KeyModifier {
|
| + NONE,
|
| + SHIFT = 1,
|
| + CONTROL = 2,
|
| + ALT = 4
|
| +};
|
| +
|
| +// Helper function to send keystrokes via the SendInput function.
|
| +// mnemonic_char: The keystroke to be sent.
|
| +// modifiers: Combination with Alt, Ctrl, Shift, etc.
|
| +void SendMnemonic(
|
| + WORD mnemonic_char, KeyModifier modifiers) {
|
| + INPUT keys[4] = {0}; // Keyboard events
|
| + int key_count = 0; // Number of generated events
|
| +
|
| + if (modifiers & SHIFT) {
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = VK_SHIFT;
|
| + keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
|
| + key_count++;
|
| + }
|
| +
|
| + if (modifiers & CONTROL) {
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = VK_CONTROL;
|
| + keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
|
| + key_count++;
|
| + }
|
| +
|
| + if (modifiers & ALT) {
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = VK_MENU;
|
| + keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
|
| + key_count++;
|
| + }
|
| +
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = mnemonic_char;
|
| + keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
|
| + key_count++;
|
| +
|
| + bool should_sleep = key_count > 1;
|
| +
|
| + // Send key downs.
|
| + for (int i = 0; i < key_count; i++) {
|
| + SendInput(1, &keys[ i ], sizeof(keys[0]));
|
| + keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
|
| + if (should_sleep)
|
| + Sleep(10);
|
| + }
|
| +
|
| + // Now send key ups in reverse order.
|
| + for (int i = key_count; i; i--) {
|
| + SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
|
| + if (should_sleep)
|
| + Sleep(10);
|
| + }
|
| }
|
|
|
| +// Helper function to Exit metro chrome cleanly. If we are in the foreground
|
| +// then we try and exit by sending an Alt+F4 key combination to the core
|
| +// window which ensures that the chrome application tile does not show up in
|
| +// the running metro apps list on the top left corner.
|
| +void MetroExit(HWND core_window) {
|
| + if ((core_window != NULL) && (core_window == ::GetForegroundWindow())) {
|
| + DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
|
| + SendMnemonic(VK_F4, ALT);
|
| + } else {
|
| + globals.app_exit->Exit();
|
| + }
|
| +}
|
| +
|
| class ChromeChannelListener : public IPC::Listener {
|
| public:
|
| ChromeChannelListener(base::MessageLoop* ui_loop, ChromeAppViewAsh* app_view)
|
| @@ -99,8 +166,13 @@
|
| }
|
|
|
| virtual void OnChannelError() OVERRIDE {
|
| - DVLOG(1) << "Channel error";
|
| - MetroExit();
|
| + DVLOG(1) << "Channel error. Exiting.";
|
| + MetroExit(app_view_->core_window());
|
| + // In early Windows 8 versions the code above sometimes fails so we call
|
| + // it a second time with a NULL window which just calls Exit().
|
| + ui_proxy_->PostDelayedTask(FROM_HERE,
|
| + base::Bind(&MetroExit, HWND(NULL)),
|
| + base::TimeDelta::FromMilliseconds(100));
|
| }
|
|
|
| private:
|
| @@ -561,6 +633,11 @@
|
|
|
| void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath& file_path) {
|
| DLOG(INFO) << "ChannelAppViewAsh::OnActivateDesktop\n";
|
| +
|
| + // As we are the top level window, the exiting is done async so we manage
|
| + // to execute the entire function including the final Send().
|
| + MetroExit(core_window());
|
| +
|
| // We are just executing delegate_execute here without parameters. Assumption
|
| // here is that this process will be reused by shell when asking for
|
| // IExecuteCommand interface.
|
|
|