| 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 "remoting/host/session_event_executor_win.h" | 5 #include "remoting/host/session_event_executor_win.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
| 12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 13 #include "base/win/windows_version.h" | 13 #include "base/win/windows_version.h" |
| 14 #include "ipc/ipc_channel.h" | 14 #include "ipc/ipc_channel.h" |
| 15 #include "ipc/ipc_channel_proxy.h" | 15 #include "ipc/ipc_channel_proxy.h" |
| 16 #include "remoting/host/chromoting_messages.h" | 16 #include "remoting/host/chromoting_messages.h" |
| 17 #include "remoting/host/sas_injector.h" |
| 17 #include "remoting/host/win/desktop.h" | 18 #include "remoting/host/win/desktop.h" |
| 18 #include "remoting/host/win/scoped_thread_desktop.h" | |
| 19 #include "remoting/proto/event.pb.h" | 19 #include "remoting/proto/event.pb.h" |
| 20 | 20 |
| 21 namespace { | 21 namespace { |
| 22 | 22 |
| 23 // The command line switch specifying the name of the Chromoting IPC channel. | |
| 24 const char kProcessChannelId[] = "chromoting-ipc"; | |
| 25 | |
| 26 const uint32 kUsbLeftControl = 0x0700e0; | 23 const uint32 kUsbLeftControl = 0x0700e0; |
| 27 const uint32 kUsbRightControl = 0x0700e4; | 24 const uint32 kUsbRightControl = 0x0700e4; |
| 28 const uint32 kUsbLeftAlt = 0x0700e2; | 25 const uint32 kUsbLeftAlt = 0x0700e2; |
| 29 const uint32 kUsbRightAlt = 0x0700e6; | 26 const uint32 kUsbRightAlt = 0x0700e6; |
| 30 const uint32 kUsbDelete = 0x07004c; | 27 const uint32 kUsbDelete = 0x07004c; |
| 31 | 28 |
| 32 bool CheckCtrlAndAltArePressed(const std::set<uint32>& pressed_keys) { | 29 bool CheckCtrlAndAltArePressed(const std::set<uint32>& pressed_keys) { |
| 33 size_t ctrl_keys = pressed_keys.count(kUsbLeftControl) + | 30 size_t ctrl_keys = pressed_keys.count(kUsbLeftControl) + |
| 34 pressed_keys.count(kUsbRightControl); | 31 pressed_keys.count(kUsbRightControl); |
| 35 size_t alt_keys = pressed_keys.count(kUsbLeftAlt) + | 32 size_t alt_keys = pressed_keys.count(kUsbLeftAlt) + |
| 36 pressed_keys.count(kUsbRightAlt); | 33 pressed_keys.count(kUsbRightAlt); |
| 37 return ctrl_keys != 0 && alt_keys != 0 && | 34 return ctrl_keys != 0 && alt_keys != 0 && |
| 38 (ctrl_keys + alt_keys == pressed_keys.size()); | 35 (ctrl_keys + alt_keys == pressed_keys.size()); |
| 39 } | 36 } |
| 40 | 37 |
| 41 // Emulates Secure Attention Sequence (Ctrl+Alt+Del) by switching to | |
| 42 // the Winlogon desktop and injecting Ctrl+Alt+Del as a hot key. | |
| 43 // N.B. Windows XP/W2K3 only. | |
| 44 void EmulateSecureAttentionSequence() { | |
| 45 const wchar_t kWinlogonDesktopName[] = L"Winlogon"; | |
| 46 const wchar_t kSasWindowClassName[] = L"SAS window class"; | |
| 47 const wchar_t kSasWindowTitle[] = L"SAS window"; | |
| 48 | |
| 49 scoped_ptr<remoting::Desktop> winlogon_desktop( | |
| 50 remoting::Desktop::GetDesktop(kWinlogonDesktopName)); | |
| 51 if (!winlogon_desktop.get()) | |
| 52 return; | |
| 53 | |
| 54 remoting::ScopedThreadDesktop desktop; | |
| 55 if (!desktop.SetThreadDesktop(winlogon_desktop.Pass())) | |
| 56 return; | |
| 57 | |
| 58 HWND window = FindWindow(kSasWindowClassName, kSasWindowTitle); | |
| 59 if (!window) | |
| 60 return; | |
| 61 | |
| 62 PostMessage(window, | |
| 63 WM_HOTKEY, | |
| 64 0, | |
| 65 MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE)); | |
| 66 } | |
| 67 | |
| 68 } // namespace | 38 } // namespace |
| 69 | 39 |
| 70 namespace remoting { | 40 namespace remoting { |
| 71 | 41 |
| 72 using protocol::ClipboardEvent; | 42 using protocol::ClipboardEvent; |
| 73 using protocol::MouseEvent; | 43 using protocol::MouseEvent; |
| 74 using protocol::KeyEvent; | 44 using protocol::KeyEvent; |
| 75 | 45 |
| 76 SessionEventExecutorWin::SessionEventExecutorWin( | 46 SessionEventExecutorWin::SessionEventExecutorWin( |
| 77 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | 47 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
| 78 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | 48 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| 79 scoped_ptr<EventExecutor> nested_executor) | 49 scoped_ptr<EventExecutor> nested_executor) |
| 80 : nested_executor_(nested_executor.Pass()), | 50 : nested_executor_(nested_executor.Pass()), |
| 81 task_runner_(main_task_runner), | 51 task_runner_(main_task_runner), |
| 82 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), | 52 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
| 83 weak_ptr_(weak_ptr_factory_.GetWeakPtr()) { | 53 weak_ptr_(weak_ptr_factory_.GetWeakPtr()) { |
| 84 // Let |weak_ptr_| be used on the |task_runner_| thread. | 54 // Let |weak_ptr_| be used on the |task_runner_| thread. |
| 85 // |weak_ptr_| and |weak_ptr_factory_| share a ThreadChecker, so the | 55 // |weak_ptr_| and |weak_ptr_factory_| share a ThreadChecker, so the |
| 86 // following line affects both of them. | 56 // following line affects both of them. |
| 87 weak_ptr_factory_.DetachFromThread(); | 57 weak_ptr_factory_.DetachFromThread(); |
| 88 | |
| 89 std::string channel_name = | |
| 90 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kProcessChannelId); | |
| 91 | |
| 92 // Connect to the Chromoting IPC channel if the name was passed in the command | |
| 93 // line. | |
| 94 if (!channel_name.empty()) { | |
| 95 chromoting_channel_.reset(new IPC::ChannelProxy( | |
| 96 channel_name, IPC::Channel::MODE_CLIENT, this, io_task_runner)); | |
| 97 } | |
| 98 } | 58 } |
| 99 | 59 |
| 100 SessionEventExecutorWin::~SessionEventExecutorWin() { | 60 SessionEventExecutorWin::~SessionEventExecutorWin() { |
| 101 } | 61 } |
| 102 | 62 |
| 103 void SessionEventExecutorWin::OnSessionStarted( | 63 void SessionEventExecutorWin::OnSessionStarted( |
| 104 scoped_ptr<protocol::ClipboardStub> client_clipboard) { | 64 scoped_ptr<protocol::ClipboardStub> client_clipboard) { |
| 105 if (!task_runner_->BelongsToCurrentThread()) { | 65 if (!task_runner_->BelongsToCurrentThread()) { |
| 106 task_runner_->PostTask( | 66 task_runner_->PostTask( |
| 107 FROM_HERE, | 67 FROM_HERE, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 // HostEventDispatcher should drop events lacking the pressed field. | 110 // HostEventDispatcher should drop events lacking the pressed field. |
| 151 DCHECK(event.has_pressed()); | 111 DCHECK(event.has_pressed()); |
| 152 | 112 |
| 153 if (event.has_usb_keycode()) { | 113 if (event.has_usb_keycode()) { |
| 154 if (event.pressed()) { | 114 if (event.pressed()) { |
| 155 // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed. | 115 // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed. |
| 156 if (event.usb_keycode() == kUsbDelete && | 116 if (event.usb_keycode() == kUsbDelete && |
| 157 CheckCtrlAndAltArePressed(pressed_keys_)) { | 117 CheckCtrlAndAltArePressed(pressed_keys_)) { |
| 158 VLOG(3) << "Sending Secure Attention Sequence to console"; | 118 VLOG(3) << "Sending Secure Attention Sequence to console"; |
| 159 | 119 |
| 160 if (base::win::GetVersion() == base::win::VERSION_XP) { | 120 if (sas_injector_.get() == NULL) |
| 161 EmulateSecureAttentionSequence(); | 121 sas_injector_ = SasInjector::Create(); |
| 162 } else if (chromoting_channel_.get()) { | 122 sas_injector_->InjectSas(); |
| 163 chromoting_channel_->Send(new ChromotingHostMsg_SendSasToConsole()); | |
| 164 } | |
| 165 } | 123 } |
| 166 | 124 |
| 167 pressed_keys_.insert(event.usb_keycode()); | 125 pressed_keys_.insert(event.usb_keycode()); |
| 168 } else { | 126 } else { |
| 169 pressed_keys_.erase(event.usb_keycode()); | 127 pressed_keys_.erase(event.usb_keycode()); |
| 170 } | 128 } |
| 171 } | 129 } |
| 172 | 130 |
| 173 SwitchToInputDesktop(); | 131 SwitchToInputDesktop(); |
| 174 nested_executor_->InjectKeyEvent(event); | 132 nested_executor_->InjectKeyEvent(event); |
| 175 } | 133 } |
| 176 | 134 |
| 177 void SessionEventExecutorWin::InjectMouseEvent(const MouseEvent& event) { | 135 void SessionEventExecutorWin::InjectMouseEvent(const MouseEvent& event) { |
| 178 if (!task_runner_->BelongsToCurrentThread()) { | 136 if (!task_runner_->BelongsToCurrentThread()) { |
| 179 task_runner_->PostTask( | 137 task_runner_->PostTask( |
| 180 FROM_HERE, | 138 FROM_HERE, |
| 181 base::Bind(&SessionEventExecutorWin::InjectMouseEvent, | 139 base::Bind(&SessionEventExecutorWin::InjectMouseEvent, |
| 182 weak_ptr_, event)); | 140 weak_ptr_, event)); |
| 183 return; | 141 return; |
| 184 } | 142 } |
| 185 | 143 |
| 186 SwitchToInputDesktop(); | 144 SwitchToInputDesktop(); |
| 187 nested_executor_->InjectMouseEvent(event); | 145 nested_executor_->InjectMouseEvent(event); |
| 188 } | 146 } |
| 189 | 147 |
| 190 bool SessionEventExecutorWin::OnMessageReceived(const IPC::Message& message) { | |
| 191 return false; | |
| 192 } | |
| 193 | |
| 194 void SessionEventExecutorWin::SwitchToInputDesktop() { | 148 void SessionEventExecutorWin::SwitchToInputDesktop() { |
| 195 // Switch to the desktop receiving user input if different from the current | 149 // Switch to the desktop receiving user input if different from the current |
| 196 // one. | 150 // one. |
| 197 scoped_ptr<Desktop> input_desktop = Desktop::GetInputDesktop(); | 151 scoped_ptr<Desktop> input_desktop = Desktop::GetInputDesktop(); |
| 198 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { | 152 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { |
| 199 // If SetThreadDesktop() fails, the thread is still assigned a desktop. | 153 // If SetThreadDesktop() fails, the thread is still assigned a desktop. |
| 200 // So we can continue capture screen bits, just from a diffected desktop. | 154 // So we can continue capture screen bits, just from a diffected desktop. |
| 201 desktop_.SetThreadDesktop(input_desktop.Pass()); | 155 desktop_.SetThreadDesktop(input_desktop.Pass()); |
| 202 } | 156 } |
| 203 } | 157 } |
| 204 | 158 |
| 205 } // namespace remoting | 159 } // namespace remoting |
| OLD | NEW |