summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authoralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-30 04:04:57 +0000
committeralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-30 04:04:57 +0000
commit31014afc104172d9607ba2a1f14cec4b3a671216 (patch)
tree5e34843f6f9b8dd6ec572b52a991d2c15bfa7ece /remoting
parentdf61e2ba8a51419639ed39dc58a25e783005a2cd (diff)
downloadchromium_src-31014afc104172d9607ba2a1f14cec4b3a671216.zip
chromium_src-31014afc104172d9607ba2a1f14cec4b3a671216.tar.gz
chromium_src-31014afc104172d9607ba2a1f14cec4b3a671216.tar.bz2
Added support of keyboard, mouse and clipboard events to DesktopSessionAgent.
BUG=134694 Review URL: https://chromiumcodereview.appspot.com/11417094 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170393 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/base/util.cc32
-rw-r--r--remoting/base/util.h3
-rw-r--r--remoting/base/util_unittest.cc34
-rw-r--r--remoting/host/chromoting_messages.h20
-rw-r--r--remoting/host/desktop_process.cc6
-rw-r--r--remoting/host/desktop_session_agent.cc146
-rw-r--r--remoting/host/desktop_session_agent.h23
-rw-r--r--remoting/host/desktop_session_agent_posix.cc10
-rw-r--r--remoting/host/desktop_session_agent_win.cc7
-rw-r--r--remoting/host/desktop_session_proxy.cc64
-rw-r--r--remoting/host/desktop_session_proxy.h14
-rw-r--r--remoting/host/ipc_desktop_environment.cc4
-rw-r--r--remoting/host/ipc_event_executor.cc37
-rw-r--r--remoting/host/ipc_event_executor.h44
-rw-r--r--remoting/remoting.gyp2
15 files changed, 441 insertions, 5 deletions
diff --git a/remoting/base/util.cc b/remoting/base/util.cc
index 77b1c5d..6e656bf 100644
--- a/remoting/base/util.cc
+++ b/remoting/base/util.cc
@@ -302,4 +302,36 @@ std::string ReplaceCrLfByLf(const std::string& in) {
return out;
}
+bool StringIsUtf8(const char* data, size_t length) {
+ const char* ptr = data;
+ const char* ptr_end = data + length;
+ while (ptr != ptr_end) {
+ if ((*ptr & 0x80) == 0) {
+ // Single-byte symbol.
+ ++ptr;
+ } else if ((*ptr & 0xc0) == 0x80 || (*ptr & 0xfe) == 0xfe) {
+ // Invalid first byte.
+ return false;
+ } else {
+ // First byte of a multi-byte symbol. The bits from 2 to 6 are the count
+ // of continuation bytes (up to 5 of them).
+ for (char first = *ptr << 1; first & 0x80; first <<= 1) {
+ ++ptr;
+
+ // Missing continuation byte.
+ if (ptr == ptr_end)
+ return false;
+
+ // Invalid continuation byte.
+ if ((*ptr & 0xc0) != 0x80)
+ return false;
+ }
+
+ ++ptr;
+ }
+ }
+
+ return true;
+}
+
} // namespace remoting
diff --git a/remoting/base/util.h b/remoting/base/util.h
index a628cb0..a627c92 100644
--- a/remoting/base/util.h
+++ b/remoting/base/util.h
@@ -96,6 +96,9 @@ std::string ReplaceLfByCrLf(const std::string& in);
// Replaces every occurrence of "\r\n" in a string by "\n".
std::string ReplaceCrLfByLf(const std::string& in);
+// Checks if the given string is a valid UTF-8 string.
+bool StringIsUtf8(const char* data, size_t length);
+
} // namespace remoting
#endif // REMOTING_BASE_UTIL_H_
diff --git a/remoting/base/util_unittest.cc b/remoting/base/util_unittest.cc
index 19579776..4fc190d 100644
--- a/remoting/base/util_unittest.cc
+++ b/remoting/base/util_unittest.cc
@@ -253,4 +253,38 @@ TEST(ReplaceCrLfByLfTest, Speed) {
}
}
+TEST(StringIsUtf8Test, Basic) {
+ EXPECT_TRUE(StringIsUtf8("", 0));
+ EXPECT_TRUE(StringIsUtf8("\0", 1));
+ EXPECT_TRUE(StringIsUtf8("abc", 3));
+ EXPECT_TRUE(StringIsUtf8("\xc0\x80", 2));
+ EXPECT_TRUE(StringIsUtf8("\xe0\x80\x80", 3));
+ EXPECT_TRUE(StringIsUtf8("\xf0\x80\x80\x80", 4));
+ EXPECT_TRUE(StringIsUtf8("\xf8\x80\x80\x80\x80", 5));
+ EXPECT_TRUE(StringIsUtf8("\xfc\x80\x80\x80\x80\x80", 6));
+
+ // Not enough continuation characters
+ EXPECT_FALSE(StringIsUtf8("\xc0", 1));
+ EXPECT_FALSE(StringIsUtf8("\xe0\x80", 2));
+ EXPECT_FALSE(StringIsUtf8("\xf0\x80\x80", 3));
+ EXPECT_FALSE(StringIsUtf8("\xf8\x80\x80\x80", 4));
+ EXPECT_FALSE(StringIsUtf8("\xfc\x80\x80\x80\x80", 5));
+
+ // One more continuation character than needed
+ EXPECT_FALSE(StringIsUtf8("\xc0\x80\x80", 3));
+ EXPECT_FALSE(StringIsUtf8("\xe0\x80\x80\x80", 4));
+ EXPECT_FALSE(StringIsUtf8("\xf0\x80\x80\x80\x80", 5));
+ EXPECT_FALSE(StringIsUtf8("\xf8\x80\x80\x80\x80\x80", 6));
+ EXPECT_FALSE(StringIsUtf8("\xfc\x80\x80\x80\x80\x80\x80", 7));
+
+ // Invalid first byte
+ EXPECT_FALSE(StringIsUtf8("\xfe\x80\x80\x80\x80\x80\x80", 7));
+ EXPECT_FALSE(StringIsUtf8("\xff\x80\x80\x80\x80\x80\x80", 7));
+
+ // Invalid continuation byte
+ EXPECT_FALSE(StringIsUtf8("\xc0\x00", 2));
+ EXPECT_FALSE(StringIsUtf8("\xc0\x40", 2));
+ EXPECT_FALSE(StringIsUtf8("\xc0\xc0", 2));
+}
+
} // namespace remoting
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
index 7c202c9..2a58f55 100644
--- a/remoting/host/chromoting_messages.h
+++ b/remoting/host/chromoting_messages.h
@@ -159,6 +159,11 @@ IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CaptureCompleted,
IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CursorShapeChanged,
std::string /* serialized_cursor_shape */ )
+// Carries a clipboard event from the desktop session agent to the client.
+// |serialized_event| is a serialized protocol::ClipboardEvent.
+IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_InjectClipboardEvent,
+ std::string /* serialized_event */ )
+
//-----------------------------------------------------------------------------
// Chromoting messages sent from the network to the desktop process.
@@ -172,3 +177,18 @@ IPC_MESSAGE_CONTROL1(ChromotingNetworkDesktopMsg_InvalidateRegion,
std::vector<SkIRect> /* invalid_region */ )
IPC_MESSAGE_CONTROL0(ChromotingNetworkDesktopMsg_CaptureFrame)
+
+// Carries a clipboard event from the client to the desktop session agent.
+// |serialized_event| is a serialized protocol::ClipboardEvent.
+IPC_MESSAGE_CONTROL1(ChromotingNetworkDesktopMsg_InjectClipboardEvent,
+ std::string /* serialized_event */ )
+
+// Carries a keyboard event from the client to the desktop session agent.
+// |serialized_event| is a serialized protocol::KeyEvent.
+IPC_MESSAGE_CONTROL1(ChromotingNetworkDesktopMsg_InjectKeyEvent,
+ std::string /* serialized_event */ )
+
+// Carries a mouse event from the client to the desktop session agent.
+// |serialized_event| is a serialized protocol::MouseEvent.
+IPC_MESSAGE_CONTROL1(ChromotingNetworkDesktopMsg_InjectMouseEvent,
+ std::string /* serialized_event */ )
diff --git a/remoting/host/desktop_process.cc b/remoting/host/desktop_process.cc
index ddab4da..6997e22 100644
--- a/remoting/host/desktop_process.cc
+++ b/remoting/host/desktop_process.cc
@@ -64,6 +64,11 @@ void DesktopProcess::OnChannelError() {
bool DesktopProcess::Start() {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
+ // Launch the input thread.
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner =
+ AutoThread::CreateWithType("Input thread", caller_task_runner_,
+ MessageLoop::TYPE_IO);
+
// Launch the I/O thread.
scoped_refptr<AutoThreadTaskRunner> io_task_runner =
AutoThread::CreateWithType("I/O thread", caller_task_runner_,
@@ -75,6 +80,7 @@ bool DesktopProcess::Start() {
// Create a desktop agent.
desktop_agent_ = DesktopSessionAgent::Create(caller_task_runner_,
+ input_task_runner,
io_task_runner,
video_capture_task_runner);
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index 5c028d0..bb5024d 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -10,12 +10,56 @@
#include "ipc/ipc_message_macros.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/base/capture_data.h"
+#include "remoting/base/constants.h"
+#include "remoting/base/util.h"
#include "remoting/host/chromoting_messages.h"
+#include "remoting/host/event_executor.h"
#include "remoting/proto/control.pb.h"
+#include "remoting/proto/event.pb.h"
+#include "remoting/protocol/clipboard_stub.h"
#include "third_party/skia/include/core/SkRegion.h"
namespace remoting {
+namespace {
+
+// USB to XKB keycode map table.
+#define USB_KEYMAP(usb, xkb, win, mac) {usb, xkb}
+#include "ui/base/keycodes/usb_keycode_map.h"
+#undef USB_KEYMAP
+
+// Routes local clipboard events though the IPC channel to the network process.
+class DesktopSesssionClipboardStub : public protocol::ClipboardStub {
+ public:
+ explicit DesktopSesssionClipboardStub(
+ scoped_refptr<DesktopSessionAgent> desktop_session_agent);
+ virtual ~DesktopSesssionClipboardStub();
+
+ // protocol::ClipboardStub implementation.
+ virtual void InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) OVERRIDE;
+
+ private:
+ scoped_refptr<DesktopSessionAgent> desktop_session_agent_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopSesssionClipboardStub);
+};
+
+DesktopSesssionClipboardStub::DesktopSesssionClipboardStub(
+ scoped_refptr<DesktopSessionAgent> desktop_session_agent)
+ : desktop_session_agent_(desktop_session_agent) {
+}
+
+DesktopSesssionClipboardStub::~DesktopSesssionClipboardStub() {
+}
+
+void DesktopSesssionClipboardStub::InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) {
+ desktop_session_agent_->InjectClipboardEvent(event);
+}
+
+} // namespace
+
DesktopSessionAgent::~DesktopSessionAgent() {
DCHECK(!network_channel_);
DCHECK(!video_capturer_);
@@ -32,7 +76,14 @@ bool DesktopSessionAgent::OnMessageReceived(const IPC::Message& message) {
OnInvalidateRegion)
IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_SharedBufferCreated,
OnSharedBufferCreated)
+ IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectClipboardEvent,
+ OnInjectClipboardEvent)
+ IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectKeyEvent,
+ OnInjectKeyEvent)
+ IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectMouseEvent,
+ OnInjectMouseEvent)
IPC_END_MESSAGE_MAP()
+
return handled;
}
@@ -123,6 +174,20 @@ void DesktopSessionAgent::OnCursorShapeChanged(
serialized_cursor_shape));
}
+void DesktopSessionAgent::InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) {
+ DCHECK(caller_task_runner()->BelongsToCurrentThread());
+
+ std::string serialized_event;
+ if (!event.SerializeToString(&serialized_event)) {
+ LOG(ERROR) << "Failed to serialize protocol::ClipboardEvent.";
+ return;
+ }
+
+ SendToNetwork(
+ new ChromotingDesktopNetworkMsg_InjectClipboardEvent(serialized_event));
+}
+
bool DesktopSessionAgent::Start(const base::Closure& disconnected_task,
IPC::PlatformFileForTransit* desktop_pipe_out) {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
@@ -133,6 +198,13 @@ bool DesktopSessionAgent::Start(const base::Closure& disconnected_task,
if (!CreateChannelForNetworkProcess(desktop_pipe_out, &network_channel_))
return false;
+ // Create and start the event executor.
+ event_executor_ = EventExecutor::Create(input_task_runner(),
+ caller_task_runner());
+ scoped_ptr<protocol::ClipboardStub> clipboard_stub(
+ new DesktopSesssionClipboardStub(this));
+ event_executor_->Start(clipboard_stub.Pass());
+
// Start the video capturer.
video_capture_task_runner()->PostTask(
FROM_HERE, base::Bind(&DesktopSessionAgent::StartVideoCapturer, this));
@@ -145,6 +217,8 @@ void DesktopSessionAgent::Stop() {
// Make sure the channel is closed.
network_channel_.reset();
+ event_executor_.reset();
+
// Stop the video capturer.
video_capture_task_runner()->PostTask(
FROM_HERE, base::Bind(&DesktopSessionAgent::StopVideoCapturer, this));
@@ -211,6 +285,76 @@ void DesktopSessionAgent::OnSharedBufferCreated(int id) {
}
}
+void DesktopSessionAgent::OnInjectClipboardEvent(
+ const std::string& serialized_event) {
+ DCHECK(caller_task_runner()->BelongsToCurrentThread());
+
+ protocol::ClipboardEvent event;
+ if (!event.ParseFromString(serialized_event)) {
+ LOG(ERROR) << "Failed to parse protocol::ClipboardEvent.";
+ return;
+ }
+
+ // Currently we only handle UTF-8 text.
+ if (event.mime_type().compare(kMimeTypeTextUtf8) != 0)
+ return;
+
+ if (!StringIsUtf8(event.data().c_str(), event.data().length())) {
+ LOG(ERROR) << "ClipboardEvent: data is not UTF-8 encoded.";
+ return;
+ }
+
+ event_executor_->InjectClipboardEvent(event);
+}
+
+void DesktopSessionAgent::OnInjectKeyEvent(
+ const std::string& serialized_event) {
+ DCHECK(caller_task_runner()->BelongsToCurrentThread());
+
+ protocol::KeyEvent event;
+ if (!event.ParseFromString(serialized_event)) {
+ LOG(ERROR) << "Failed to parse protocol::KeyEvent.";
+ return;
+ }
+
+ // Ignore unknown keycodes.
+ if (event.has_usb_keycode() &&
+ UsbKeycodeToNativeKeycode(event.usb_keycode()) == kInvalidKeycode) {
+ LOG(ERROR) << "KeyEvent: unknown USB keycode: "
+ << std::hex << event.usb_keycode() << std::dec;
+ return;
+ }
+
+ event_executor_->InjectKeyEvent(event);
+}
+
+void DesktopSessionAgent::OnInjectMouseEvent(
+ const std::string& serialized_event) {
+ DCHECK(caller_task_runner()->BelongsToCurrentThread());
+
+ protocol::MouseEvent event;
+ if (!event.ParseFromString(serialized_event)) {
+ LOG(ERROR) << "Failed to parse protocol::MouseEvent.";
+ return;
+ }
+
+ // Validate the specified button index.
+ if (event.has_button() &&
+ !(protocol::MouseEvent::BUTTON_LEFT <= event.button() &&
+ event.button() < protocol::MouseEvent::BUTTON_MAX)) {
+ LOG(ERROR) << "MouseEvent: unknown button: " << event.button();
+ return;
+ }
+
+ // Do not allow negative coordinates.
+ if (event.has_x())
+ event.set_x(std::max(0, event.x()));
+ if (event.has_y())
+ event.set_y(std::max(0, event.y()));
+
+ event_executor_->InjectMouseEvent(event);
+}
+
void DesktopSessionAgent::SendToNetwork(IPC::Message* message) {
if (!caller_task_runner()->BelongsToCurrentThread()) {
caller_task_runner()->PostTask(
@@ -248,9 +392,11 @@ void DesktopSessionAgent::StopVideoCapturer() {
DesktopSessionAgent::DesktopSessionAgent(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
: caller_task_runner_(caller_task_runner),
+ input_task_runner_(input_task_runner),
io_task_runner_(io_task_runner),
video_capture_task_runner_(video_capture_task_runner),
next_shared_buffer_id_(1) {
diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h
index a8d9303..d7d5c90 100644
--- a/remoting/host/desktop_session_agent.h
+++ b/remoting/host/desktop_session_agent.h
@@ -17,6 +17,7 @@
#include "remoting/base/shared_buffer.h"
#include "remoting/base/shared_buffer_factory.h"
#include "remoting/host/video_frame_capturer.h"
+#include "remoting/protocol/clipboard_stub.h"
#include "third_party/skia/include/core/SkRect.h"
namespace IPC {
@@ -27,6 +28,7 @@ class Message;
namespace remoting {
class AutoThreadTaskRunner;
+class EventExecutor;
// Provides screen/audio capturing and input injection services for
// the network process.
@@ -38,6 +40,7 @@ class DesktopSessionAgent
public:
static scoped_refptr<DesktopSessionAgent> Create(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner);
@@ -56,6 +59,10 @@ class DesktopSessionAgent
virtual void OnCursorShapeChanged(
scoped_ptr<protocol::CursorShapeInfo> cursor_shape) OVERRIDE;
+ // Forwards a local clipboard event though the IPC channel to the network
+ // process.
+ void InjectClipboardEvent(const protocol::ClipboardEvent& event);
+
// Creates desktop integration components and a connected IPC channel to be
// used to access them. The client end of the channel is returned in
// the variable pointed by |desktop_pipe_out|.
@@ -71,6 +78,7 @@ class DesktopSessionAgent
protected:
DesktopSessionAgent(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner);
@@ -92,6 +100,11 @@ class DesktopSessionAgent
// Handles SharedBufferCreated notification from the client.
void OnSharedBufferCreated(int id);
+ // Handles event executor requests from the client.
+ void OnInjectClipboardEvent(const std::string& serialized_event);
+ void OnInjectKeyEvent(const std::string& serialized_event);
+ void OnInjectMouseEvent(const std::string& serialized_event);
+
// Sends a message to the network process.
void SendToNetwork(IPC::Message* message);
@@ -107,6 +120,10 @@ class DesktopSessionAgent
return caller_task_runner_;
}
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner() const {
+ return input_task_runner_;
+ }
+
scoped_refptr<AutoThreadTaskRunner> io_task_runner() const {
return io_task_runner_;
}
@@ -119,6 +136,9 @@ class DesktopSessionAgent
// Task runner on which public methods of this class should be called.
scoped_refptr<AutoThreadTaskRunner> caller_task_runner_;
+ // Task runner on which keyboard/mouse input is injected.
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner_;
+
// Task runner used by the IPC channel.
scoped_refptr<AutoThreadTaskRunner> io_task_runner_;
@@ -129,6 +149,9 @@ class DesktopSessionAgent
// desktop channel has been disconnected.
base::Closure disconnected_task_;
+ // Executes keyboard, mouse and clipboard events.
+ scoped_ptr<EventExecutor> event_executor_;
+
// IPC channel connecting the desktop process with the network process.
scoped_ptr<IPC::ChannelProxy> network_channel_;
diff --git a/remoting/host/desktop_session_agent_posix.cc b/remoting/host/desktop_session_agent_posix.cc
index cc198bd..d357d23 100644
--- a/remoting/host/desktop_session_agent_posix.cc
+++ b/remoting/host/desktop_session_agent_posix.cc
@@ -23,6 +23,7 @@ class DesktopSessionAgentPosix : public DesktopSessionAgent {
public:
DesktopSessionAgentPosix(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner);
@@ -39,9 +40,10 @@ class DesktopSessionAgentPosix : public DesktopSessionAgent {
DesktopSessionAgentPosix::DesktopSessionAgentPosix(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
- : DesktopSessionAgent(caller_task_runner, io_task_runner,
+ : DesktopSessionAgent(caller_task_runner, input_task_runner, io_task_runner,
video_capture_task_runner) {
}
@@ -89,10 +91,12 @@ bool DesktopSessionAgentPosix::CreateChannelForNetworkProcess(
// static
scoped_refptr<DesktopSessionAgent> DesktopSessionAgent::Create(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner) {
- return scoped_refptr<DesktopSessionAgent>(new DesktopSessionAgentPosix(
- caller_task_runner, io_task_runner, video_capture_task_runner));
+ return scoped_refptr<DesktopSessionAgent>(
+ new DesktopSessionAgentPosix(caller_task_runner, input_task_runner,
+ io_task_runner, video_capture_task_runner));
}
} // namespace remoting
diff --git a/remoting/host/desktop_session_agent_win.cc b/remoting/host/desktop_session_agent_win.cc
index 6ef4f01..0117439 100644
--- a/remoting/host/desktop_session_agent_win.cc
+++ b/remoting/host/desktop_session_agent_win.cc
@@ -25,6 +25,7 @@ class DesktopSessionAgentWin : public DesktopSessionAgent {
public:
DesktopSessionAgentWin(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner);
@@ -41,9 +42,11 @@ class DesktopSessionAgentWin : public DesktopSessionAgent {
DesktopSessionAgentWin::DesktopSessionAgentWin(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
: DesktopSessionAgent(caller_task_runner,
+ input_task_runner,
io_task_runner,
video_capture_task_runner) {
}
@@ -87,10 +90,12 @@ bool DesktopSessionAgentWin::CreateChannelForNetworkProcess(
// static
scoped_refptr<DesktopSessionAgent> DesktopSessionAgent::Create(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
+ scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner) {
return scoped_refptr<DesktopSessionAgent>(new DesktopSessionAgentWin(
- caller_task_runner, io_task_runner, video_capture_task_runner));
+ caller_task_runner, input_task_runner, io_task_runner,
+ video_capture_task_runner));
}
} // namespace remoting
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 840f061..d5af3c4 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -15,6 +15,7 @@
#include "remoting/host/chromoting_messages.h"
#include "remoting/host/ipc_video_frame_capturer.h"
#include "remoting/proto/control.pb.h"
+#include "remoting/proto/event.pb.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
@@ -44,6 +45,8 @@ bool DesktopSessionProxy::OnMessageReceived(const IPC::Message& message) {
OnCreateSharedBuffer)
IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_ReleaseSharedBuffer,
OnReleaseSharedBuffer)
+ IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_InjectClipboardEvent,
+ OnInjectClipboardEvent)
IPC_END_MESSAGE_MAP()
return handled;
@@ -123,6 +126,53 @@ void DesktopSessionProxy::Disconnect() {
}
}
+void DesktopSessionProxy::InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) {
+ DCHECK(caller_task_runner_->BelongsToCurrentThread());
+
+ std::string serialized_event;
+ if (!event.SerializeToString(&serialized_event)) {
+ LOG(ERROR) << "Failed to serialize protocol::ClipboardEvent.";
+ return;
+ }
+
+ SendToDesktop(
+ new ChromotingNetworkDesktopMsg_InjectClipboardEvent(serialized_event));
+}
+
+void DesktopSessionProxy::InjectKeyEvent(const protocol::KeyEvent& event) {
+ DCHECK(caller_task_runner_->BelongsToCurrentThread());
+
+ std::string serialized_event;
+ if (!event.SerializeToString(&serialized_event)) {
+ LOG(ERROR) << "Failed to serialize protocol::KeyEvent.";
+ return;
+ }
+
+ SendToDesktop(
+ new ChromotingNetworkDesktopMsg_InjectKeyEvent(serialized_event));
+}
+
+void DesktopSessionProxy::InjectMouseEvent(const protocol::MouseEvent& event) {
+ DCHECK(caller_task_runner_->BelongsToCurrentThread());
+
+ std::string serialized_event;
+ if (!event.SerializeToString(&serialized_event)) {
+ LOG(ERROR) << "Failed to serialize protocol::MouseEvent.";
+ return;
+ }
+
+ SendToDesktop(
+ new ChromotingNetworkDesktopMsg_InjectMouseEvent(serialized_event));
+}
+
+void DesktopSessionProxy::StartEventExecutor(
+ scoped_ptr<protocol::ClipboardStub> client_clipboard) {
+ DCHECK(caller_task_runner_->BelongsToCurrentThread());
+
+ client_clipboard_ = client_clipboard.Pass();
+}
+
void DesktopSessionProxy::InvalidateRegion(const SkRegion& invalid_region) {
if (!caller_task_runner_->BelongsToCurrentThread()) {
caller_task_runner_->PostTask(
@@ -274,6 +324,20 @@ void DesktopSessionProxy::OnCursorShapeChanged(
PostCursorShape(cursor_shape.Pass());
}
+void DesktopSessionProxy::OnInjectClipboardEvent(
+ const std::string& serialized_event) {
+ DCHECK(caller_task_runner_->BelongsToCurrentThread());
+
+ protocol::ClipboardEvent event;
+ if (!event.ParseFromString(serialized_event)) {
+ LOG(ERROR) << "Failed to parse protocol::ClipboardEvent.";
+ return;
+ }
+
+ client_clipboard_->InjectClipboardEvent(event);
+}
+
+
void DesktopSessionProxy::PostCaptureCompleted(
scoped_refptr<CaptureData> capture_data) {
if (!video_capture_task_runner_->BelongsToCurrentThread()) {
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h
index ad80310..c0344fc 100644
--- a/remoting/host/desktop_session_proxy.h
+++ b/remoting/host/desktop_session_proxy.h
@@ -14,6 +14,8 @@
#include "ipc/ipc_platform_file.h"
#include "remoting/base/shared_buffer.h"
#include "remoting/host/video_frame_capturer.h"
+#include "remoting/proto/event.pb.h"
+#include "remoting/protocol/clipboard_stub.h"
#include "third_party/skia/include/core/SkRegion.h"
#if defined(OS_WIN)
@@ -72,6 +74,12 @@ class DesktopSessionProxy
// StopVideoCapturer() has been called will be silently dropped.
void StopVideoCapturer();
+ // APIs used to implement the EventExecutor interface.
+ void InjectClipboardEvent(const protocol::ClipboardEvent& event);
+ void InjectKeyEvent(const protocol::KeyEvent& event);
+ void InjectMouseEvent(const protocol::MouseEvent& event);
+ void StartEventExecutor(scoped_ptr<protocol::ClipboardStub> client_clipboard);
+
private:
friend class base::RefCountedThreadSafe<DesktopSessionProxy>;
virtual ~DesktopSessionProxy();
@@ -101,6 +109,9 @@ class DesktopSessionProxy
// |video_capturer_|.
void PostCursorShape(scoped_ptr<protocol::CursorShapeInfo> cursor_shape);
+ // Handles InjectClipboardEvent request from the desktop integration process.
+ void OnInjectClipboardEvent(const std::string& serialized_event);
+
// Sends a message to the desktop session agent. The message is silently
// deleted if the channel is broken.
void SendToDesktop(IPC::Message* message);
@@ -112,6 +123,9 @@ class DesktopSessionProxy
// Task runner on which |video_capturer_delegate_| will be invoked.
scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner_;
+ // Points to the client stub passed to StartEventExecutor().
+ scoped_ptr<protocol::ClipboardStub> client_clipboard_;
+
// IPC channel to the desktop session agent.
scoped_ptr<IPC::ChannelProxy> desktop_channel_;
diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc
index 57fc3f2..383fc4f 100644
--- a/remoting/host/ipc_desktop_environment.cc
+++ b/remoting/host/ipc_desktop_environment.cc
@@ -17,6 +17,7 @@
#include "remoting/host/desktop_session_connector.h"
#include "remoting/host/desktop_session_proxy.h"
#include "remoting/host/event_executor.h"
+#include "remoting/host/ipc_event_executor.h"
#include "remoting/host/ipc_video_frame_capturer.h"
#include "remoting/host/video_frame_capturer.h"
@@ -35,7 +36,8 @@ IpcDesktopEnvironment::IpcDesktopEnvironment(
ClientSession* client)
: DesktopEnvironment(
AudioCapturer::Create(),
- EventExecutor::Create(input_task_runner, ui_task_runner),
+ scoped_ptr<EventExecutor>(
+ new IpcEventExecutor(desktop_session_proxy)),
scoped_ptr<VideoFrameCapturer>(
new IpcVideoFrameCapturer(desktop_session_proxy))),
network_task_runner_(network_task_runner),
diff --git a/remoting/host/ipc_event_executor.cc b/remoting/host/ipc_event_executor.cc
new file mode 100644
index 0000000..33d41ae
--- /dev/null
+++ b/remoting/host/ipc_event_executor.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/host/ipc_event_executor.h"
+
+#include "remoting/host/desktop_session_proxy.h"
+
+namespace remoting {
+
+IpcEventExecutor::IpcEventExecutor(
+ scoped_refptr<DesktopSessionProxy> desktop_session_proxy)
+ : desktop_session_proxy_(desktop_session_proxy) {
+}
+
+IpcEventExecutor::~IpcEventExecutor() {
+}
+
+void IpcEventExecutor::InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) {
+ desktop_session_proxy_->InjectClipboardEvent(event);
+}
+
+void IpcEventExecutor::InjectKeyEvent(const protocol::KeyEvent& event) {
+ desktop_session_proxy_->InjectKeyEvent(event);
+}
+
+void IpcEventExecutor::InjectMouseEvent(const protocol::MouseEvent& event) {
+ desktop_session_proxy_->InjectMouseEvent(event);
+}
+
+void IpcEventExecutor::Start(
+ scoped_ptr<protocol::ClipboardStub> client_clipboard) {
+ desktop_session_proxy_->StartEventExecutor(client_clipboard.Pass());
+}
+
+} // namespace remoting
diff --git a/remoting/host/ipc_event_executor.h b/remoting/host/ipc_event_executor.h
new file mode 100644
index 0000000..5316783
--- /dev/null
+++ b/remoting/host/ipc_event_executor.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_HOST_IPC_EVENT_EXECUTOR_H_
+#define REMOTING_HOST_IPC_EVENT_EXECUTOR_H_
+
+#include "base/memory/ref_counted.h"
+#include "remoting/host/event_executor.h"
+#include "remoting/proto/event.pb.h"
+
+namespace remoting {
+
+class DesktopSessionProxy;
+
+// Routes EventExecutor calls though the IPC channel to the desktop session
+// agent running in the desktop integration process.
+class IpcEventExecutor : public EventExecutor {
+ public:
+ IpcEventExecutor(scoped_refptr<DesktopSessionProxy> desktop_session_proxy);
+ virtual ~IpcEventExecutor();
+
+ // ClipboardStub interface.
+ virtual void InjectClipboardEvent(
+ const protocol::ClipboardEvent& event) OVERRIDE;
+
+ // InputStub interface.
+ virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE;
+ virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE;
+
+ // EventExecutor interface.
+ virtual void Start(
+ scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE;
+
+ private:
+ // Wraps the IPC channel to the desktop process.
+ scoped_refptr<DesktopSessionProxy> desktop_session_proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(IpcEventExecutor);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_IPC_EVENT_EXECUTOR_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index eef4607..4f6f287 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -1594,6 +1594,8 @@
'host/ipc_desktop_environment_factory.h',
'host/ipc_desktop_environment.cc',
'host/ipc_desktop_environment.h',
+ 'host/ipc_event_executor.cc',
+ 'host/ipc_event_executor.h',
'host/ipc_video_frame_capturer.cc',
'host/ipc_video_frame_capturer.h',
'host/it2me_host_user_interface.cc',