summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/host/desktop_session_win.cc4
-rw-r--r--remoting/host/installer/win/chromoting.wxs2
-rw-r--r--remoting/host/win/chromoting_lib_idl.templ5
-rw-r--r--remoting/host/win/rdp_client.cc19
-rw-r--r--remoting/host/win/rdp_client.h3
-rw-r--r--remoting/host/win/rdp_client_window.cc113
-rw-r--r--remoting/host/win/rdp_client_window.h4
-rw-r--r--remoting/host/win/rdp_desktop_session.cc6
-rw-r--r--remoting/host/win/rdp_desktop_session.h1
-rw-r--r--remoting/host/win/session_input_injector.cc2
10 files changed, 153 insertions, 6 deletions
diff --git a/remoting/host/desktop_session_win.cc b/remoting/host/desktop_session_win.cc
index 5d126d2..1ae4fa5 100644
--- a/remoting/host/desktop_session_win.cc
+++ b/remoting/host/desktop_session_win.cc
@@ -287,9 +287,7 @@ void RdpSession::SetScreenResolution(const ScreenResolution& resolution) {
void RdpSession::InjectSas() {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
- // TODO(alexeypa): implement SAS injection for RDP sessions here.
- // See http://crbug.com/137696.
- NOTIMPLEMENTED();
+ rdp_desktop_session_->InjectSas();
}
RdpSession::EventHandler::EventHandler(
diff --git a/remoting/host/installer/win/chromoting.wxs b/remoting/host/installer/win/chromoting.wxs
index bc1aaa9..077e373 100644
--- a/remoting/host/installer/win/chromoting.wxs
+++ b/remoting/host/installer/win/chromoting.wxs
@@ -36,7 +36,7 @@
<?define ControllerProgid =
"ChromotingElevatedController.ElevatedController" ?>
- <?define IRdpDesktopSessionId = "{126c22bc-34ef-4cfb-83ef-9b8ada3391e8}" ?>
+ <?define IRdpDesktopSessionId = "{1d68cef0-dbc0-4745-9755-055b28d9e5cc}" ?>
<?define IRdpDesktopSessionEventHandlerId =
"{987bca97-9d40-42fc-a00d-e6a701261af5}" ?>
diff --git a/remoting/host/win/chromoting_lib_idl.templ b/remoting/host/win/chromoting_lib_idl.templ
index 4ba0ab3b..fd6b5f4 100644
--- a/remoting/host/win/chromoting_lib_idl.templ
+++ b/remoting/host/win/chromoting_lib_idl.templ
@@ -88,7 +88,7 @@ interface IRdpDesktopSessionEventHandler : IUnknown {
[
object,
- uuid(126c22bc-34ef-4cfb-83ef-9b8ada3391e8),
+ uuid(1d68cef0-dbc0-4745-9755-055b28d9e5cc),
nonextensible,
helpstring("IRdpDesktopSession Interface"),
pointer_default(unique)
@@ -105,6 +105,9 @@ interface IRdpDesktopSession : IUnknown {
[ id(3), helpstring("Changes the screen resolution.") ]
HRESULT ChangeResolution([in] long width, [in] long height);
+
+ [ id(4), helpstring("Sends Secure Attention Sequence to the session.") ]
+ HRESULT InjectSas();
};
[
diff --git a/remoting/host/win/rdp_client.cc b/remoting/host/win/rdp_client.cc
index 8838398..edf7ddf 100644
--- a/remoting/host/win/rdp_client.cc
+++ b/remoting/host/win/rdp_client.cc
@@ -56,6 +56,9 @@ class RdpClient::Core
// Initiates a graceful shutdown of the RDP connection.
void Disconnect();
+ // Sends Secure Attention Sequence to the session.
+ void InjectSas();
+
// RdpClientWindow::EventHandler interface.
virtual void OnConnected() OVERRIDE;
virtual void OnDisconnected() OVERRIDE;
@@ -129,6 +132,12 @@ RdpClient::~RdpClient() {
core_->Disconnect();
}
+void RdpClient::InjectSas() {
+ DCHECK(CalledOnValidThread());
+
+ core_->InjectSas();
+}
+
RdpClient::Core::Core(
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
@@ -207,6 +216,16 @@ void RdpClient::Core::Disconnect() {
}
}
+void RdpClient::Core::InjectSas() {
+ if (!ui_task_runner_->BelongsToCurrentThread()) {
+ ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::InjectSas, this));
+ return;
+ }
+
+ if (rdp_client_window_)
+ rdp_client_window_->InjectSas();
+}
+
void RdpClient::Core::OnConnected() {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
DCHECK(rdp_client_window_);
diff --git a/remoting/host/win/rdp_client.h b/remoting/host/win/rdp_client.h
index 07a0238..a0537a9 100644
--- a/remoting/host/win/rdp_client.h
+++ b/remoting/host/win/rdp_client.h
@@ -43,6 +43,9 @@ class RdpClient : public base::NonThreadSafe {
EventHandler* event_handler);
virtual ~RdpClient();
+ // Sends Secure Attention Sequence to the session.
+ void InjectSas();
+
private:
// The actual implementation resides in Core class.
class Core;
diff --git a/remoting/host/win/rdp_client_window.cc b/remoting/host/win/rdp_client_window.cc
index 1f81538..e9bcdac 100644
--- a/remoting/host/win/rdp_client_window.cc
+++ b/remoting/host/win/rdp_client_window.cc
@@ -6,8 +6,11 @@
#include <wtsdefs.h>
+#include <list>
+
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/string16.h"
#include "base/threading/thread_local.h"
#include "base/utf_string_conversions.h"
#include "base/win/scoped_bstr.h"
@@ -23,10 +26,53 @@ const long kDisconnectReasonLocalNotError = 1;
const long kDisconnectReasonRemoteByUser = 2;
const long kDisconnectReasonByServer = 3;
+// Maximum length of a window class name including the terminating NULL.
+const int kMaxWindowClassLength = 256;
+
+// Each member of the array returned by GetKeyboardState() contains status data
+// for a virtual key. If the high-order bit is 1, the key is down; otherwise, it
+// is up.
+const BYTE kKeyPressedFlag = 0x80;
+
+const int kKeyboardStateLength = 256;
+
+// The RDP control creates 'IHWindowClass' window to handle keyboard input.
+const wchar_t kRdpInputWindowClass[] = L"IHWindowClass";
+
// Points to a per-thread instance of the window activation hook handle.
base::LazyInstance<base::ThreadLocalPointer<RdpClientWindow::WindowHook> >
g_window_hook = LAZY_INSTANCE_INITIALIZER;
+// Finds a child window with the class name matching |class_name|. Unlike
+// FindWindowEx() this function walks the tree of windows recursively. The walk
+// is done in breadth-first order. The function returns NULL if the child window
+// could not be found.
+HWND FindWindowRecursively(HWND parent, const string16& class_name) {
+ std::list<HWND> windows;
+ windows.push_back(parent);
+
+ while (!windows.empty()) {
+ HWND child = FindWindowEx(windows.front(), NULL, NULL, NULL);
+ while (child != NULL) {
+ // See if the window class name matches |class_name|.
+ WCHAR name[kMaxWindowClassLength];
+ int length = GetClassName(child, name, arraysize(name));
+ if (string16(name, length) == class_name)
+ return child;
+
+ // Remember the window to look through its children.
+ windows.push_back(child);
+
+ // Go to the next child.
+ child = FindWindowEx(windows.front(), child, NULL, NULL);
+ }
+
+ windows.pop_front();
+ }
+
+ return NULL;
+}
+
} // namespace
// Used to close any windows activated on a particular thread. It installs
@@ -87,6 +133,68 @@ void RdpClientWindow::Disconnect() {
SendMessage(WM_CLOSE);
}
+void RdpClientWindow::InjectSas() {
+ if (!m_hWnd)
+ return;
+
+ // Fins the window handling the keyboard input.
+ HWND input_window = FindWindowRecursively(m_hWnd, kRdpInputWindowClass);
+ if (!input_window) {
+ LOG(ERROR) << "Failed to find the window handling the keyboard input.";
+ return;
+ }
+
+ VLOG(3) << "Injecting Ctrl+Alt+End to emulate SAS.";
+
+ BYTE keyboard_state[kKeyboardStateLength];
+ if (!GetKeyboardState(keyboard_state)) {
+ LOG_GETLASTERROR(ERROR) << "Failed to get the keyboard state.";
+ return;
+ }
+
+ // This code is running in Session 0, so we expect no keys to be pressed.
+ DCHECK(!(keyboard_state[VK_CONTROL] & kKeyPressedFlag));
+ DCHECK(!(keyboard_state[VK_MENU] & kKeyPressedFlag));
+ DCHECK(!(keyboard_state[VK_END] & kKeyPressedFlag));
+
+ // Map virtual key codes to scan codes.
+ UINT control = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC);
+ UINT alt = MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC);
+ UINT end = MapVirtualKey(VK_END, MAPVK_VK_TO_VSC) | KF_EXTENDED;
+ UINT up = KF_UP | KF_REPEAT;
+
+ // Press 'Ctrl'.
+ keyboard_state[VK_CONTROL] |= kKeyPressedFlag;
+ keyboard_state[VK_LCONTROL] |= kKeyPressedFlag;
+ CHECK(SetKeyboardState(keyboard_state));
+ SendMessage(input_window, WM_KEYDOWN, VK_CONTROL, MAKELPARAM(1, control));
+
+ // Press 'Alt'.
+ keyboard_state[VK_MENU] |= kKeyPressedFlag;
+ keyboard_state[VK_LMENU] |= kKeyPressedFlag;
+ CHECK(SetKeyboardState(keyboard_state));
+ SendMessage(input_window, WM_KEYDOWN, VK_MENU,
+ MAKELPARAM(1, alt | KF_ALTDOWN));
+
+ // Press and release 'End'.
+ SendMessage(input_window, WM_KEYDOWN, VK_END,
+ MAKELPARAM(1, end | KF_ALTDOWN));
+ SendMessage(input_window, WM_KEYUP, VK_END,
+ MAKELPARAM(1, end | up | KF_ALTDOWN));
+
+ // Release 'Alt'.
+ keyboard_state[VK_MENU] &= ~kKeyPressedFlag;
+ keyboard_state[VK_LMENU] &= ~kKeyPressedFlag;
+ CHECK(SetKeyboardState(keyboard_state));
+ SendMessage(input_window, WM_KEYUP, VK_MENU, MAKELPARAM(1, alt | up));
+
+ // Release 'Ctrl'.
+ keyboard_state[VK_CONTROL] &= ~kKeyPressedFlag;
+ keyboard_state[VK_LCONTROL] &= ~kKeyPressedFlag;
+ CHECK(SetKeyboardState(keyboard_state));
+ SendMessage(input_window, WM_KEYUP, VK_CONTROL, MAKELPARAM(1, control | up));
+}
+
void RdpClientWindow::OnClose() {
if (!client_) {
NotifyDisconnected();
@@ -182,6 +290,11 @@ LRESULT RdpClientWindow::OnCreate(CREATESTRUCT* create_struct) {
if (FAILED(result))
goto done;
+ // Enable the Ctrl+Alt+Del screen.
+ result = client_settings_->put_DisableCtrlAltDel(0);
+ if (FAILED(result))
+ goto done;
+
// Disable printer and clipboard redirection.
result = client_settings_->put_DisableRdpdr(FALSE);
if (FAILED(result))
diff --git a/remoting/host/win/rdp_client_window.h b/remoting/host/win/rdp_client_window.h
index c4b71d2..f7517db 100644
--- a/remoting/host/win/rdp_client_window.h
+++ b/remoting/host/win/rdp_client_window.h
@@ -77,6 +77,10 @@ class RdpClientWindow
// until it receives OnDisconnected() notification.
void Disconnect();
+ // Emulates pressing Ctrl+Alt+End combination that is translated to Secure
+ // Attention Sequence by the ActiveX control.
+ void InjectSas();
+
private:
typedef IDispEventImpl<1, RdpClientWindow,
&__uuidof(mstsc::IMsTscAxEvents),
diff --git a/remoting/host/win/rdp_desktop_session.cc b/remoting/host/win/rdp_desktop_session.cc
index 977ac33..1b12266 100644
--- a/remoting/host/win/rdp_desktop_session.cc
+++ b/remoting/host/win/rdp_desktop_session.cc
@@ -41,6 +41,12 @@ STDMETHODIMP RdpDesktopSession::ChangeResolution(long width, long height) {
return E_NOTIMPL;
}
+STDMETHODIMP RdpDesktopSession::InjectSas() {
+ if (client_)
+ client_->InjectSas();
+ return S_OK;
+}
+
void RdpDesktopSession::OnRdpConnected(const net::IPEndPoint& client_endpoint) {
net::SockaddrStorage sockaddr;
CHECK(client_endpoint.ToSockAddr(sockaddr.addr, &sockaddr.addr_len));
diff --git a/remoting/host/win/rdp_desktop_session.h b/remoting/host/win/rdp_desktop_session.h
index f48512b..ff08107 100644
--- a/remoting/host/win/rdp_desktop_session.h
+++ b/remoting/host/win/rdp_desktop_session.h
@@ -47,6 +47,7 @@ class __declspec(uuid(RDP_DESKTOP_SESSION_CLSID)) RdpDesktopSession
IRdpDesktopSessionEventHandler* event_handler);
STDMETHOD(Disconnect)();
STDMETHOD(ChangeResolution)(long width, long height);
+ STDMETHOD(InjectSas)();
DECLARE_NO_REGISTRY()
diff --git a/remoting/host/win/session_input_injector.cc b/remoting/host/win/session_input_injector.cc
index 73b9cf3..4c763ee 100644
--- a/remoting/host/win/session_input_injector.cc
+++ b/remoting/host/win/session_input_injector.cc
@@ -143,7 +143,7 @@ void SessionInputInjectorWin::Core::InjectKeyEvent(const KeyEvent& event) {
// Simulate secure attention sequence if Ctrl-Alt-Del was just pressed.
if (event.usb_keycode() == kUsbDelete &&
CheckCtrlAndAltArePressed(pressed_keys_)) {
- VLOG(3) << "Sending Secure Attention Sequence to console";
+ VLOG(3) << "Sending Secure Attention Sequence to the session";
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
if (!sas_injector_)