diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-30 04:04:57 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-30 04:04:57 +0000 |
commit | 31014afc104172d9607ba2a1f14cec4b3a671216 (patch) | |
tree | 5e34843f6f9b8dd6ec572b52a991d2c15bfa7ece /remoting | |
parent | df61e2ba8a51419639ed39dc58a25e783005a2cd (diff) | |
download | chromium_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.cc | 32 | ||||
-rw-r--r-- | remoting/base/util.h | 3 | ||||
-rw-r--r-- | remoting/base/util_unittest.cc | 34 | ||||
-rw-r--r-- | remoting/host/chromoting_messages.h | 20 | ||||
-rw-r--r-- | remoting/host/desktop_process.cc | 6 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent.cc | 146 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent.h | 23 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent_posix.cc | 10 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent_win.cc | 7 | ||||
-rw-r--r-- | remoting/host/desktop_session_proxy.cc | 64 | ||||
-rw-r--r-- | remoting/host/desktop_session_proxy.h | 14 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment.cc | 4 | ||||
-rw-r--r-- | remoting/host/ipc_event_executor.cc | 37 | ||||
-rw-r--r-- | remoting/host/ipc_event_executor.h | 44 | ||||
-rw-r--r-- | remoting/remoting.gyp | 2 |
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', |