Commit ebe85a81 authored by Gary Kacmarcik's avatar Gary Kacmarcik Committed by Commit Bot

[Chromoting] Fix mouse when single display selected in multi-mon

Previous code would always translate the mouse coords relative to the
upper-left corner of the entire display, instead of relative to the
currently selected display.

This cl changes the mouse input scaler to be a DesktopRect instead of
a DesktopSize because we need to keep track of the origin for proper
mouse event scaling.

Change-Id: I397c51280187c7a8e023e8a41940b6f37b39eb7f
Reviewed-on: https://chromium-review.googlesource.com/c/1429339
Commit-Queue: Gary Kacmarcik <garykac@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#625325}
parent 7a340f40
...@@ -184,11 +184,12 @@ void ChromotingClient::SetVideoLayout(const protocol::VideoLayout& layout) { ...@@ -184,11 +184,12 @@ void ChromotingClient::SetVideoLayout(const protocol::VideoLayout& layout) {
user_interface_->SetDesktopSize(size_pixels, user_interface_->SetDesktopSize(size_pixels,
webrtc::DesktopVector(x_dpi, y_dpi)); webrtc::DesktopVector(x_dpi, y_dpi));
mouse_input_scaler_.set_input_size(size_pixels); mouse_input_scaler_.set_input_size(
webrtc::DesktopRect::MakeSize(size_pixels));
mouse_input_scaler_.set_output_size( mouse_input_scaler_.set_output_size(
connection_->config().protocol() == protocol::SessionConfig::Protocol::ICE connection_->config().protocol() == protocol::SessionConfig::Protocol::ICE
? size_pixels ? webrtc::DesktopRect::MakeSize(size_pixels)
: size_dips); : webrtc::DesktopRect::MakeSize(size_dips));
} }
void ChromotingClient::InjectClipboardEvent( void ChromotingClient::InjectClipboardEvent(
......
...@@ -326,7 +326,7 @@ void ChromotingInstance::DidChangeView(const pp::View& view) { ...@@ -326,7 +326,7 @@ void ChromotingInstance::DidChangeView(const pp::View& view) {
plugin_view_ = view; plugin_view_ = view;
webrtc::DesktopSize size( webrtc::DesktopSize size(
webrtc::DesktopSize(view.GetRect().width(), view.GetRect().height())); webrtc::DesktopSize(view.GetRect().width(), view.GetRect().height()));
mouse_input_filter_.set_input_size(size); mouse_input_filter_.set_input_size(webrtc::DesktopRect::MakeSize(size));
touch_input_scaler_.set_input_size(size); touch_input_scaler_.set_input_size(size);
if (video_renderer_) if (video_renderer_)
...@@ -503,7 +503,7 @@ void ChromotingInstance::SetDesktopSize(const webrtc::DesktopSize& size, ...@@ -503,7 +503,7 @@ void ChromotingInstance::SetDesktopSize(const webrtc::DesktopSize& size,
const webrtc::DesktopVector& dpi) { const webrtc::DesktopVector& dpi) {
DCHECK(!dpi.is_zero()); DCHECK(!dpi.is_zero());
mouse_input_filter_.set_output_size(size); mouse_input_filter_.set_output_size(webrtc::DesktopRect::MakeSize(size));
touch_input_scaler_.set_output_size(size); touch_input_scaler_.set_output_size(size);
std::unique_ptr<base::DictionaryValue> data(new base::DictionaryValue()); std::unique_ptr<base::DictionaryValue> data(new base::DictionaryValue());
...@@ -738,7 +738,7 @@ void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) { ...@@ -738,7 +738,7 @@ void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) {
if (!plugin_view_.is_null()) { if (!plugin_view_.is_null()) {
webrtc::DesktopSize size(plugin_view_.GetRect().width(), webrtc::DesktopSize size(plugin_view_.GetRect().width(),
plugin_view_.GetRect().height()); plugin_view_.GetRect().height());
mouse_input_filter_.set_input_size(size); mouse_input_filter_.set_input_size(webrtc::DesktopRect::MakeSize(size));
touch_input_scaler_.set_input_size(size); touch_input_scaler_.set_input_size(size);
} }
......
...@@ -246,8 +246,13 @@ void ClientSession::SelectDesktopDisplay( ...@@ -246,8 +246,13 @@ void ClientSession::SelectDesktopDisplay(
// Default to fullscreen if unable to parse id. // Default to fullscreen if unable to parse id.
id = webrtc::kFullDesktopScreenId; id = webrtc::kFullDesktopScreenId;
} }
// Invalid display index defaults to showing all displays.
if (!desktop_display_info_.GetDisplayInfo(id)) {
id = webrtc::kFullDesktopScreenId;
}
} }
video_stream_->SelectSource(id); video_stream_->SelectSource(id);
show_display_id_ = id;
} }
void ClientSession::OnConnectionAuthenticating() { void ClientSession::OnConnectionAuthenticating() {
...@@ -264,6 +269,8 @@ void ClientSession::OnConnectionAuthenticated() { ...@@ -264,6 +269,8 @@ void ClientSession::OnConnectionAuthenticated() {
is_authenticated_ = true; is_authenticated_ = true;
desktop_display_info_.Reset();
if (max_duration_ > base::TimeDelta()) { if (max_duration_ > base::TimeDelta()) {
max_duration_timer_.Start( max_duration_timer_.Start(
FROM_HERE, max_duration_, FROM_HERE, max_duration_,
...@@ -481,21 +488,31 @@ void ClientSession::OnVideoSizeChanged(protocol::VideoStream* video_stream, ...@@ -481,21 +488,31 @@ void ClientSession::OnVideoSizeChanged(protocol::VideoStream* video_stream,
const webrtc::DesktopSize& size, const webrtc::DesktopSize& size,
const webrtc::DesktopVector& dpi) { const webrtc::DesktopVector& dpi) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
webrtc::DesktopVector origin;
mouse_clamping_filter_.set_output_size(size); if (show_display_id_ != webrtc::kFullDesktopScreenId) {
const DisplayGeometry* display_info =
desktop_display_info_.GetDisplayInfo(show_display_id_);
if (display_info) {
origin.set(display_info->x, display_info->y);
}
}
mouse_clamping_filter_.set_output_size(
webrtc::DesktopRect::MakeOriginSize(origin, size));
switch (connection_->session()->config().protocol()) { switch (connection_->session()->config().protocol()) {
case protocol::SessionConfig::Protocol::ICE: case protocol::SessionConfig::Protocol::ICE:
mouse_clamping_filter_.set_input_size(size); mouse_clamping_filter_.set_input_size(
webrtc::DesktopRect::MakeSize(size));
break; break;
case protocol::SessionConfig::Protocol::WEBRTC: { case protocol::SessionConfig::Protocol::WEBRTC: {
// When using WebRTC protocol the client sends mouse coordinates in DIPs, // When using WebRTC protocol the client sends mouse coordinates in DIPs,
// while InputInjector expects them in physical pixels. // while InputInjector expects them in physical pixels.
// TODO(sergeyu): Fix InputInjector implementations to use DIPs as well. // TODO(sergeyu): Fix InputInjector implementations to use DIPs as well.
webrtc::DesktopSize size_dips(size.width() * kDefaultDpi / dpi.x(), webrtc::DesktopSize size_dips =
size.height() * kDefaultDpi / dpi.y()); DesktopDisplayInfo::CalcSizeDips(size, dpi.x(), dpi.y());
mouse_clamping_filter_.set_input_size(size_dips); mouse_clamping_filter_.set_input_size(
webrtc::DesktopRect::MakeSize(size_dips));
// Generate and send VideoLayout message. // Generate and send VideoLayout message.
protocol::VideoLayout layout; protocol::VideoLayout layout;
...@@ -547,10 +564,9 @@ void ClientSession::OnDesktopDisplayChanged( ...@@ -547,10 +564,9 @@ void ClientSession::OnDesktopDisplayChanged(
// Calc desktop scaled geometry (in DIPs) // Calc desktop scaled geometry (in DIPs)
// See comment in OnVideoSizeChanged() for details. // See comment in OnVideoSizeChanged() for details.
int scaled_width = (max_x - min_x) * kDefaultDpi / dpi_x; const webrtc::DesktopSize size(max_x - min_x, max_y - min_y);
int scaled_height = (max_y - min_y) * kDefaultDpi / dpi_y; webrtc::DesktopSize size_dips =
webrtc::DesktopSize size_dips(scaled_width, scaled_height); DesktopDisplayInfo::CalcSizeDips(size, dpi_x, dpi_y);
mouse_clamping_filter_.set_input_size(size_dips);
// Generate and send VideoLayout message. // Generate and send VideoLayout message.
protocol::VideoLayout layout; protocol::VideoLayout layout;
...@@ -563,8 +579,8 @@ void ClientSession::OnDesktopDisplayChanged( ...@@ -563,8 +579,8 @@ void ClientSession::OnDesktopDisplayChanged(
video_track = layout.add_video_track(); video_track = layout.add_video_track();
video_track->set_position_x(0); video_track->set_position_x(0);
video_track->set_position_y(0); video_track->set_position_y(0);
video_track->set_width(scaled_width); video_track->set_width(size_dips.width());
video_track->set_height(scaled_height); video_track->set_height(size_dips.height());
video_track->set_x_dpi(dpi_x); video_track->set_x_dpi(dpi_x);
video_track->set_y_dpi(dpi_y); video_track->set_y_dpi(dpi_y);
...@@ -578,10 +594,14 @@ void ClientSession::OnDesktopDisplayChanged( ...@@ -578,10 +594,14 @@ void ClientSession::OnDesktopDisplayChanged(
video_track->set_y_dpi(dpi_y); video_track->set_y_dpi(dpi_y);
// Add a VideoTrackLayout entry for each separate display. // Add a VideoTrackLayout entry for each separate display.
desktop_display_info_.Reset();
for (int display_id = 0; display_id < displays->video_track_size(); for (int display_id = 0; display_id < displays->video_track_size();
display_id++) { display_id++) {
protocol::VideoTrackLayout display = displays->video_track(display_id);
desktop_display_info_.AddDisplayFrom(display);
protocol::VideoTrackLayout* video_track = layout.add_video_track(); protocol::VideoTrackLayout* video_track = layout.add_video_track();
video_track->CopyFrom(displays->video_track(display_id)); video_track->CopyFrom(display);
} }
connection_->client_stub()->SetVideoLayout(layout); connection_->client_stub()->SetVideoLayout(layout);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "remoting/host/client_session_control.h" #include "remoting/host/client_session_control.h"
#include "remoting/host/client_session_details.h" #include "remoting/host/client_session_details.h"
#include "remoting/host/desktop_display_info.h"
#include "remoting/host/desktop_environment_options.h" #include "remoting/host/desktop_environment_options.h"
#include "remoting/host/host_experiment_session_plugin.h" #include "remoting/host/host_experiment_session_plugin.h"
#include "remoting/host/host_extension_session_manager.h" #include "remoting/host/host_extension_session_manager.h"
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
#include "remoting/protocol/mouse_input_filter.h" #include "remoting/protocol/mouse_input_filter.h"
#include "remoting/protocol/pairing_registry.h" #include "remoting/protocol/pairing_registry.h"
#include "remoting/protocol/video_stream.h" #include "remoting/protocol/video_stream.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace remoting { namespace remoting {
...@@ -245,6 +247,13 @@ class ClientSession : public protocol::HostStub, ...@@ -245,6 +247,13 @@ class ClientSession : public protocol::HostStub,
// Used to apply client-requested changes in screen resolution. // Used to apply client-requested changes in screen resolution.
std::unique_ptr<ScreenControls> screen_controls_; std::unique_ptr<ScreenControls> screen_controls_;
// Contains the most recently gathered info about the desktop displays;
DesktopDisplayInfo desktop_display_info_;
// The id of the desktop display to show to the user.
// Default is webrtc::kFullDesktopScreenId which shows all displays.
webrtc::ScreenId show_display_id_ = webrtc::kFullDesktopScreenId;
// The pairing registry for PIN-less authentication. // The pairing registry for PIN-less authentication.
scoped_refptr<protocol::PairingRegistry> pairing_registry_; scoped_refptr<protocol::PairingRegistry> pairing_registry_;
......
...@@ -107,6 +107,15 @@ class ClientSessionTest : public testing::Test { ...@@ -107,6 +107,15 @@ class ClientSessionTest : public testing::Test {
void TearDown() override; void TearDown() override;
protected: protected:
// Fake multi-monitor setup.
static const int kDisplay1Width =
protocol::FakeDesktopCapturer::kWidth; // 800
static const int kDisplay1Height =
protocol::FakeDesktopCapturer::kHeight; // 600
static const int kDisplay2Width = 1024;
static const int kDisplay2Height = 768;
static const int kDisplay2YOffset = 35;
// Creates the client session from a FakeSession instance. // Creates the client session from a FakeSession instance.
void CreateClientSession(std::unique_ptr<protocol::FakeSession> session); void CreateClientSession(std::unique_ptr<protocol::FakeSession> session);
...@@ -119,7 +128,34 @@ class ClientSessionTest : public testing::Test { ...@@ -119,7 +128,34 @@ class ClientSessionTest : public testing::Test {
void ConnectClientSession(); void ConnectClientSession();
// Fakes video size notification from the VideoStream. // Fakes video size notification from the VideoStream.
void NotifyVideoSize(); void NotifyVideoSize(int width, int height, int dpi_x, int dpi_y);
// Add a fake display to the layout list. Used in conjunction with
// NotifyDesktopDisplaySize.
void AddDisplayToLayout(protocol::VideoLayout* displays,
int x,
int y,
int width,
int height,
int dpi_x,
int dpi_y);
// Fakes desktop display size notification from Webrtc.
void NotifyDesktopDisplaySize(
std::unique_ptr<protocol::VideoLayout> displays);
// Fakes display select request from user.
void NotifySelectDesktopDisplay(std::string id);
// Convenience methods to setup a single- or double-monitor setup.
void SetupSingleDisplay();
void SetupMultiDisplay();
// When using a multi-mon setup, this fakes the user selecting which displays
// to show.
void MultiMon_SelectFirstDisplay();
void MultiMon_SelectSecondDisplay();
void MultiMon_SelectAllDisplays();
// Message loop that will process all ClientSession tasks. // Message loop that will process all ClientSession tasks.
base::MessageLoop message_loop_; base::MessageLoop message_loop_;
...@@ -211,18 +247,142 @@ void ClientSessionTest::ConnectClientSession() { ...@@ -211,18 +247,142 @@ void ClientSessionTest::ConnectClientSession() {
client_session_->OnConnectionChannelsConnected(); client_session_->OnConnectionChannelsConnected();
} }
void ClientSessionTest::NotifyVideoSize() { void ClientSessionTest::NotifyVideoSize(int width,
int height,
int dpi_x,
int dpi_y) {
connection_->last_video_stream()->observer()->OnVideoSizeChanged( connection_->last_video_stream()->observer()->OnVideoSizeChanged(
connection_->last_video_stream().get(), connection_->last_video_stream().get(),
webrtc::DesktopSize(protocol::FakeDesktopCapturer::kWidth, webrtc::DesktopSize(width, height), webrtc::DesktopVector(dpi_x, dpi_y));
protocol::FakeDesktopCapturer::kHeight), }
webrtc::DesktopVector(kDefaultDpi, kDefaultDpi));
void ClientSessionTest::AddDisplayToLayout(protocol::VideoLayout* displays,
int x,
int y,
int width,
int height,
int dpi_x,
int dpi_y) {
protocol::VideoTrackLayout* video_track = displays->add_video_track();
video_track->set_position_x(x);
video_track->set_position_y(y);
video_track->set_width(width);
video_track->set_height(height);
video_track->set_x_dpi(dpi_x);
video_track->set_y_dpi(dpi_y);
}
void ClientSessionTest::NotifyDesktopDisplaySize(
std::unique_ptr<protocol::VideoLayout> displays) {
client_session_->OnDesktopDisplayChanged(std::move(displays));
}
void ClientSessionTest::NotifySelectDesktopDisplay(std::string id) {
protocol::SelectDesktopDisplayRequest req;
req.set_id(id);
client_session_->SelectDesktopDisplay(req);
}
// Set up a single display (default size).
void ClientSessionTest::SetupSingleDisplay() {
NotifyVideoSize(kDisplay1Width, kDisplay1Height, kDefaultDpi, kDefaultDpi);
auto displays = std::make_unique<protocol::VideoLayout>();
AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height,
kDefaultDpi, kDefaultDpi);
NotifyDesktopDisplaySize(std::move(displays));
}
// Set up multiple displays:
// +-----------+
// | 800x600 |---------------+
// | 0 | 1024x768 |
// +-----------+ 1 |
// | |
// +---------------+
void ClientSessionTest::SetupMultiDisplay() {
NotifyVideoSize(kDisplay1Width + kDisplay2Width, kDisplay2Height, kDefaultDpi,
kDefaultDpi);
auto displays = std::make_unique<protocol::VideoLayout>();
AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height,
kDefaultDpi, kDefaultDpi);
AddDisplayToLayout(displays.get(), kDisplay1Width, kDisplay2YOffset,
kDisplay2Width, kDisplay2Height, kDefaultDpi, kDefaultDpi);
NotifyDesktopDisplaySize(std::move(displays));
}
void ClientSessionTest::MultiMon_SelectFirstDisplay() {
NotifySelectDesktopDisplay("0");
NotifyVideoSize(kDisplay1Width, kDisplay1Height, kDefaultDpi, kDefaultDpi);
}
void ClientSessionTest::MultiMon_SelectSecondDisplay() {
NotifySelectDesktopDisplay("1");
NotifyVideoSize(kDisplay2Width, kDisplay2Height, kDefaultDpi, kDefaultDpi);
}
void ClientSessionTest::MultiMon_SelectAllDisplays() {
NotifySelectDesktopDisplay("all");
NotifyVideoSize(kDisplay1Width + kDisplay2Width, kDisplay2Height, kDefaultDpi,
kDefaultDpi);
}
TEST_F(ClientSessionTest, MultiMonMouseMove) {
CreateClientSession();
ConnectClientSession();
SetupMultiDisplay();
FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment()
->last_input_injector()
.get();
std::vector<protocol::MouseEvent> mouse_events;
input_injector->set_mouse_events(&mouse_events);
// These mouse events are in global (full desktop) coordinates.
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(70, 50));
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(1000, 650));
// Select second display: origin: 800,35 ; size: 1024x768
MultiMon_SelectSecondDisplay();
// This mouse event is injected relative to the second display.
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(1005, 625));
// Events should clamp to the selected display.
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(2000, 700));
// Select first display: origin: 0,0 ; size: 800x600
MultiMon_SelectFirstDisplay();
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(80, 60));
// Events should clamp to the selected display (800,600).
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(1000, 640));
// Select entire desktop again: origin: 0,0 ; size: 1824x768
MultiMon_SelectAllDisplays();
// Events should clamp to the entire desktop (800+1024, 768).
connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(2000, 1000));
client_session_->DisconnectSession(protocol::OK);
client_session_.reset();
EXPECT_EQ(7U, mouse_events.size());
EXPECT_THAT(mouse_events[0], EqualsMouseMoveEvent(70, 50));
EXPECT_THAT(mouse_events[1], EqualsMouseMoveEvent(1000, 650));
EXPECT_THAT(mouse_events[2], EqualsMouseMoveEvent(1005 + kDisplay1Width,
625 + kDisplay2YOffset));
EXPECT_THAT(mouse_events[3],
EqualsMouseMoveEvent(kDisplay1Width + kDisplay2Width - 1,
700 + kDisplay2YOffset));
EXPECT_THAT(mouse_events[4], EqualsMouseMoveEvent(80, 60));
EXPECT_THAT(mouse_events[5],
EqualsMouseMoveEvent(kDisplay1Width - 1, kDisplay1Height - 1));
EXPECT_THAT(mouse_events[6],
EqualsMouseMoveEvent(kDisplay1Width + kDisplay2Width - 1,
kDisplay2Height - 1));
} }
TEST_F(ClientSessionTest, DisableInputs) { TEST_F(ClientSessionTest, DisableInputs) {
CreateClientSession(); CreateClientSession();
ConnectClientSession(); ConnectClientSession();
NotifyVideoSize(); SetupSingleDisplay();
FakeInputInjector* input_injector = FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment() desktop_environment_factory_->last_desktop_environment()
...@@ -278,8 +438,7 @@ TEST_F(ClientSessionTest, DisableInputs) { ...@@ -278,8 +438,7 @@ TEST_F(ClientSessionTest, DisableInputs) {
TEST_F(ClientSessionTest, LocalInputTest) { TEST_F(ClientSessionTest, LocalInputTest) {
CreateClientSession(); CreateClientSession();
ConnectClientSession(); ConnectClientSession();
NotifyVideoSize(); SetupSingleDisplay();
std::vector<protocol::MouseEvent> mouse_events; std::vector<protocol::MouseEvent> mouse_events;
desktop_environment_factory_->last_desktop_environment() desktop_environment_factory_->last_desktop_environment()
...@@ -314,7 +473,7 @@ TEST_F(ClientSessionTest, LocalInputTest) { ...@@ -314,7 +473,7 @@ TEST_F(ClientSessionTest, LocalInputTest) {
TEST_F(ClientSessionTest, RestoreEventState) { TEST_F(ClientSessionTest, RestoreEventState) {
CreateClientSession(); CreateClientSession();
ConnectClientSession(); ConnectClientSession();
NotifyVideoSize(); SetupSingleDisplay();
FakeInputInjector* input_injector = FakeInputInjector* input_injector =
desktop_environment_factory_->last_desktop_environment() desktop_environment_factory_->last_desktop_environment()
...@@ -352,7 +511,7 @@ TEST_F(ClientSessionTest, RestoreEventState) { ...@@ -352,7 +511,7 @@ TEST_F(ClientSessionTest, RestoreEventState) {
TEST_F(ClientSessionTest, ClampMouseEvents) { TEST_F(ClientSessionTest, ClampMouseEvents) {
CreateClientSession(); CreateClientSession();
ConnectClientSession(); ConnectClientSession();
NotifyVideoSize(); SetupSingleDisplay();
std::vector<protocol::MouseEvent> mouse_events; std::vector<protocol::MouseEvent> mouse_events;
desktop_environment_factory_->last_desktop_environment() desktop_environment_factory_->last_desktop_environment()
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "remoting/host/desktop_display_info.h" #include "remoting/host/desktop_display_info.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "remoting/base/constants.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include <windows.h> #include <windows.h>
...@@ -40,6 +41,45 @@ bool DesktopDisplayInfo::operator!=(const DesktopDisplayInfo& other) { ...@@ -40,6 +41,45 @@ bool DesktopDisplayInfo::operator!=(const DesktopDisplayInfo& other) {
return !(*this == other); return !(*this == other);
} }
/* static */
webrtc::DesktopSize DesktopDisplayInfo::CalcSizeDips(webrtc::DesktopSize size,
int dpi_x,
int dpi_y) {
webrtc::DesktopSize size_dips(size.width() * kDefaultDpi / dpi_x,
size.height() * kDefaultDpi / dpi_y);
return size_dips;
}
void DesktopDisplayInfo::Reset() {
displays_.clear();
}
int DesktopDisplayInfo::NumDisplays() {
return displays_.size();
}
const DisplayGeometry* DesktopDisplayInfo::GetDisplayInfo(unsigned int id) {
if (id >= displays_.size())
return nullptr;
return &displays_[id];
}
void DesktopDisplayInfo::AddDisplay(DisplayGeometry* display) {
displays_.push_back(*display);
}
void DesktopDisplayInfo::AddDisplayFrom(protocol::VideoTrackLayout track) {
auto* display = new DisplayGeometry();
display->x = track.position_x();
display->y = track.position_y();
display->width = track.width();
display->height = track.height();
display->dpi = track.x_dpi();
display->bpp = kDefaultDpi;
display->is_default = false;
displays_.push_back(*display);
}
void DesktopDisplayInfo::LoadCurrentDisplayInfo() { void DesktopDisplayInfo::LoadCurrentDisplayInfo() {
displays_.clear(); displays_.clear();
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "remoting/proto/control.pb.h" #include "remoting/proto/control.pb.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace remoting { namespace remoting {
...@@ -25,6 +26,21 @@ class DesktopDisplayInfo { ...@@ -25,6 +26,21 @@ class DesktopDisplayInfo {
DesktopDisplayInfo(); DesktopDisplayInfo();
~DesktopDisplayInfo(); ~DesktopDisplayInfo();
static webrtc::DesktopSize CalcSizeDips(webrtc::DesktopSize size,
int dpi_x,
int dpi_y);
// Clear out the display info.
void Reset();
int NumDisplays();
const DisplayGeometry* GetDisplayInfo(unsigned int id);
// Add a new display with the given info to the display list.
void AddDisplay(DisplayGeometry* display);
void AddDisplayFrom(protocol::VideoTrackLayout track);
// Query the OS for the set of currently active desktop displays.
void LoadCurrentDisplayInfo(); void LoadCurrentDisplayInfo();
bool operator==(const DesktopDisplayInfo& other); bool operator==(const DesktopDisplayInfo& other);
......
...@@ -112,3 +112,25 @@ message SelectDesktopDisplayRequest { ...@@ -112,3 +112,25 @@ message SelectDesktopDisplayRequest {
// The "all" string is used to select the entire desktop. // The "all" string is used to select the entire desktop.
optional string id = 1; optional string id = 1;
} }
message DesktopDisplayInfo {
// Unique display identifier.
optional int32 id = 1;
// Position of the top left corner of this display (in pixels).
optional int32 x = 2;
optional int32 y = 3;
// Size of the display (in pixels).
optional int32 width = 4;
optional int32 height = 5;
// DPI of the screen.
optional int32 dpi = 6;
// Bits per pixel.
optional int32 bpp = 7;
// True if this is the default display.
optional bool is_default = 8;
}
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "remoting/protocol/mouse_input_filter.h" #include "remoting/protocol/mouse_input_filter.h"
#include <algorithm>
#include "base/logging.h"
#include "remoting/proto/event.pb.h" #include "remoting/proto/event.pb.h"
namespace remoting { namespace remoting {
...@@ -18,34 +21,40 @@ MouseInputFilter::MouseInputFilter(InputStub* input_stub) ...@@ -18,34 +21,40 @@ MouseInputFilter::MouseInputFilter(InputStub* input_stub)
MouseInputFilter::~MouseInputFilter() = default; MouseInputFilter::~MouseInputFilter() = default;
void MouseInputFilter::InjectMouseEvent(const MouseEvent& event) { void MouseInputFilter::InjectMouseEvent(const MouseEvent& event) {
if (input_max_.is_empty() || output_max_.is_empty()) if (input_rect_.is_empty() || output_rect_.is_empty())
return; return;
// We scale based on the maximum input & output coordinates, rather than the // We scale based on the maximum input & output coordinates, rather than the
// input and output sizes, so that it's possible to reach the edge of the // input and output sizes, so that it's possible to reach the edge of the
// output when up-scaling. We also take care to round up or down correctly, // output when up-scaling. We also take care to round up or down correctly,
// which is important when down-scaling. // which is important when down-scaling.
// After scaling, we offset by the output rect origin. This is normally (0,0),
// but will be non-zero when we are showing a single display.
MouseEvent out_event(event); MouseEvent out_event(event);
if (out_event.has_x()) { if (out_event.has_x()) {
int x = out_event.x() * output_max_.width(); int x = out_event.x() * output_rect_.width();
x = (x + input_max_.width() / 2) / input_max_.width(); x = (x + input_rect_.width() / 2) / input_rect_.width();
out_event.set_x(std::max(0, std::min(output_max_.width(), x))); out_event.set_x(output_rect_.left() +
std::max(0, std::min(output_rect_.width(), x)));
} }
if (out_event.has_y()) { if (out_event.has_y()) {
int y = out_event.y() * output_max_.height(); int y = out_event.y() * output_rect_.height();
y = (y + input_max_.height() / 2) / input_max_.height(); y = (y + input_rect_.height() / 2) / input_rect_.height();
out_event.set_y(std::max(0, std::min(output_max_.height(), y))); out_event.set_y(output_rect_.top() +
std::max(0, std::min(output_rect_.height(), y)));
} }
InputFilter::InjectMouseEvent(out_event); InputFilter::InjectMouseEvent(out_event);
} }
void MouseInputFilter::set_input_size(const webrtc::DesktopSize& size) { void MouseInputFilter::set_input_size(const webrtc::DesktopRect& rect) {
input_max_.set(size.width() - 1, size.height() - 1); input_rect_ = webrtc::DesktopRect::MakeXYWH(
rect.left(), rect.top(), rect.width() - 1, rect.height() - 1);
} }
void MouseInputFilter::set_output_size(const webrtc::DesktopSize& size) { void MouseInputFilter::set_output_size(const webrtc::DesktopRect& rect) {
output_max_.set(size.width() - 1, size.height() - 1); output_rect_ = webrtc::DesktopRect::MakeXYWH(
rect.left(), rect.top(), rect.width() - 1, rect.height() - 1);
} }
} // namespace protocol } // namespace protocol
......
...@@ -23,17 +23,18 @@ class MouseInputFilter : public InputFilter { ...@@ -23,17 +23,18 @@ class MouseInputFilter : public InputFilter {
~MouseInputFilter() override; ~MouseInputFilter() override;
// Specify the input dimensions for mouse events. // Specify the input dimensions for mouse events.
void set_input_size(const webrtc::DesktopSize& size); // This is specified in DIPs for WebRTC and pixels for ICE protocol.
void set_input_size(const webrtc::DesktopRect& r);
// Specify the output dimensions. // Specify the output dimensions (always in physical pixels).
void set_output_size(const webrtc::DesktopSize& size); void set_output_size(const webrtc::DesktopRect& r);
// InputStub overrides. // InputStub overrides.
void InjectMouseEvent(const protocol::MouseEvent& event) override; void InjectMouseEvent(const protocol::MouseEvent& event) override;
private: private:
webrtc::DesktopSize input_max_; webrtc::DesktopRect input_rect_;
webrtc::DesktopSize output_max_; webrtc::DesktopRect output_rect_;
DISALLOW_COPY_AND_ASSIGN(MouseInputFilter); DISALLOW_COPY_AND_ASSIGN(MouseInputFilter);
}; };
......
...@@ -60,7 +60,7 @@ TEST(MouseInputFilterTest, BothDimensionsZero) { ...@@ -60,7 +60,7 @@ TEST(MouseInputFilterTest, BothDimensionsZero) {
TEST(MouseInputFilterTest, InputDimensionsZero) { TEST(MouseInputFilterTest, InputDimensionsZero) {
MockInputStub mock_stub; MockInputStub mock_stub;
MouseInputFilter mouse_filter(&mock_stub); MouseInputFilter mouse_filter(&mock_stub);
mouse_filter.set_output_size(webrtc::DesktopSize(50, 50)); mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(50, 50));
EXPECT_CALL(mock_stub, InjectMouseEvent(_)) EXPECT_CALL(mock_stub, InjectMouseEvent(_))
.Times(0); .Times(0);
...@@ -72,7 +72,7 @@ TEST(MouseInputFilterTest, InputDimensionsZero) { ...@@ -72,7 +72,7 @@ TEST(MouseInputFilterTest, InputDimensionsZero) {
TEST(MouseInputFilterTest, OutputDimensionsZero) { TEST(MouseInputFilterTest, OutputDimensionsZero) {
MockInputStub mock_stub; MockInputStub mock_stub;
MouseInputFilter mouse_filter(&mock_stub); MouseInputFilter mouse_filter(&mock_stub);
mouse_filter.set_input_size(webrtc::DesktopSize(50, 50)); mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(50, 50));
EXPECT_CALL(mock_stub, InjectMouseEvent(_)) EXPECT_CALL(mock_stub, InjectMouseEvent(_))
.Times(0); .Times(0);
...@@ -84,8 +84,8 @@ TEST(MouseInputFilterTest, OutputDimensionsZero) { ...@@ -84,8 +84,8 @@ TEST(MouseInputFilterTest, OutputDimensionsZero) {
TEST(MouseInputFilterTest, NoScalingOrClipping) { TEST(MouseInputFilterTest, NoScalingOrClipping) {
MockInputStub mock_stub; MockInputStub mock_stub;
MouseInputFilter mouse_filter(&mock_stub); MouseInputFilter mouse_filter(&mock_stub);
mouse_filter.set_output_size(webrtc::DesktopSize(40,40)); mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(40, 40));
mouse_filter.set_input_size(webrtc::DesktopSize(40,40)); mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(40, 40));
{ {
InSequence s; InSequence s;
...@@ -112,8 +112,8 @@ TEST(MouseInputFilterTest, NoScalingOrClipping) { ...@@ -112,8 +112,8 @@ TEST(MouseInputFilterTest, NoScalingOrClipping) {
TEST(MouseInputFilterTest, UpScalingAndClamping) { TEST(MouseInputFilterTest, UpScalingAndClamping) {
MockInputStub mock_stub; MockInputStub mock_stub;
MouseInputFilter mouse_filter(&mock_stub); MouseInputFilter mouse_filter(&mock_stub);
mouse_filter.set_output_size(webrtc::DesktopSize(80, 80)); mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(80, 80));
mouse_filter.set_input_size(webrtc::DesktopSize(40, 40)); mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(40, 40));
{ {
InSequence s; InSequence s;
...@@ -140,8 +140,8 @@ TEST(MouseInputFilterTest, UpScalingAndClamping) { ...@@ -140,8 +140,8 @@ TEST(MouseInputFilterTest, UpScalingAndClamping) {
TEST(MouseInputFilterTest, DownScalingAndClamping) { TEST(MouseInputFilterTest, DownScalingAndClamping) {
MockInputStub mock_stub; MockInputStub mock_stub;
MouseInputFilter mouse_filter(&mock_stub); MouseInputFilter mouse_filter(&mock_stub);
mouse_filter.set_output_size(webrtc::DesktopSize(30, 30)); mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(30, 30));
mouse_filter.set_input_size(webrtc::DesktopSize(40, 40)); mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(40, 40));
{ {
InSequence s; InSequence s;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment