Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: ui/display/chromeos/touchscreen_util.cc

Issue 2540313002: Split //ui/display and create //ui/display/manager. (Closed)
Patch Set: Cleanup export header. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/display/chromeos/touchscreen_util.h"
6
7 #include <set>
8
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "ui/events/devices/input_device.h"
13
14 namespace display {
15
16 namespace {
17
18 using DisplayInfoList = std::vector<ManagedDisplayInfo*>;
19 using DeviceList = std::vector<const ui::TouchscreenDevice*>;
20
21 // Helper method to associate |display| and |device|.
22 void Associate(ManagedDisplayInfo* display,
23 const ui::TouchscreenDevice* device) {
24 display->AddInputDevice(device->id);
25 display->set_touch_support(Display::TOUCH_SUPPORT_AVAILABLE);
26 }
27
28 // Returns true if |path| is likely a USB device.
29 bool IsDeviceConnectedViaUsb(const base::FilePath& path) {
30 std::vector<base::FilePath::StringType> components;
31 path.GetComponents(&components);
32
33 for (const auto& component : components) {
34 if (base::StartsWith(component, "usb",
35 base::CompareCase::INSENSITIVE_ASCII))
36 return true;
37 }
38
39 return false;
40 }
41
42 // Returns the UDL association score between |display| and |device|. A score <=
43 // 0 means that there is no association.
44 int GetUdlAssociationScore(const ManagedDisplayInfo* display,
45 const ui::TouchscreenDevice* device) {
46 // If the devices are not both connected via USB, then there cannot be a UDL
47 // association score.
48 if (!IsDeviceConnectedViaUsb(display->sys_path()) ||
49 !IsDeviceConnectedViaUsb(device->sys_path))
50 return 0;
51
52 // The association score is simply the number of prefix path components that
53 // sysfs paths have in common.
54 std::vector<base::FilePath::StringType> display_components;
55 std::vector<base::FilePath::StringType> device_components;
56 display->sys_path().GetComponents(&display_components);
57 device->sys_path.GetComponents(&device_components);
58
59 std::size_t largest_idx = 0;
60 while (largest_idx < display_components.size() &&
61 largest_idx < device_components.size() &&
62 display_components[largest_idx] == device_components[largest_idx]) {
63 ++largest_idx;
64 }
65 return largest_idx;
66 }
67
68 // Tries to find a UDL device that best matches |display|. Returns nullptr
69 // if one is not found.
70 const ui::TouchscreenDevice* GuessBestUdlDevice(
71 const ManagedDisplayInfo* display,
72 const DeviceList& devices) {
73 int best_score = 0;
74 const ui::TouchscreenDevice* best_device = nullptr;
75
76 for (const ui::TouchscreenDevice* device : devices) {
77 int score = GetUdlAssociationScore(display, device);
78 if (score > best_score) {
79 best_score = score;
80 best_device = device;
81 }
82 }
83
84 return best_device;
85 }
86
87 void AssociateUdlDevices(DisplayInfoList* displays, DeviceList* devices) {
88 VLOG(2) << "Trying to match udl devices (" << displays->size()
89 << " displays and " << devices->size() << " devices to match)";
90
91 DisplayInfoList::iterator display_it = displays->begin();
92 while (display_it != displays->end()) {
93 ManagedDisplayInfo* display = *display_it;
94 const ui::TouchscreenDevice* device = GuessBestUdlDevice(display, *devices);
95
96 if (device) {
97 VLOG(2) << "=> Matched device " << device->name << " to display "
98 << display->name()
99 << " (score=" << GetUdlAssociationScore(display, device) << ")";
100 Associate(display, device);
101
102 display_it = displays->erase(display_it);
103 devices->erase(std::find(devices->begin(), devices->end(), device));
104
105 continue;
106 }
107
108 ++display_it;
109 }
110 }
111
112 // Returns true if |display| is internal.
113 bool IsInternalDisplay(const ManagedDisplayInfo* display) {
114 return Display::IsInternalDisplayId(display->id());
115 }
116
117 // Returns true if |device| is internal.
118 bool IsInternalDevice(const ui::TouchscreenDevice* device) {
119 return device->type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
120 }
121
122 void AssociateInternalDevices(DisplayInfoList* displays, DeviceList* devices) {
123 VLOG(2) << "Trying to match internal devices (" << displays->size()
124 << " displays and " << devices->size() << " devices to match)";
125
126 // Internal device assocation has a couple of gotchas:
127 // - There can be internal devices but no internal display, or visa-versa.
128 // - There can be multiple internal devices matching one internal display. We
129 // assume there is at most one internal display.
130 // - All internal devices must be removed from |displays| and |devices| after
131 // this function has returned, since an internal device can never be
132 // associated with an external device.
133
134 // Capture the internal display reference as we remove it from |displays|.
135 ManagedDisplayInfo* internal_display = nullptr;
136 DisplayInfoList::iterator display_it =
137 std::find_if(displays->begin(), displays->end(), &IsInternalDisplay);
138 if (display_it != displays->end()) {
139 internal_display = *display_it;
140 displays->erase(display_it);
141 }
142
143 bool matched = false;
144
145 // Remove all internal devices from |devices|. If we have an internal display,
146 // then associate the device with the display before removing it.
147 DeviceList::iterator device_it = devices->begin();
148 while (device_it != devices->end()) {
149 const ui::TouchscreenDevice* internal_device = *device_it;
150
151 // Not an internal device, skip it.
152 if (!IsInternalDevice(internal_device)) {
153 ++device_it;
154 continue;
155 }
156
157 if (internal_display) {
158 VLOG(2) << "=> Matched device " << internal_device->name << " to display "
159 << internal_display->name();
160 Associate(internal_display, internal_device);
161 matched = true;
162 } else {
163 VLOG(2) << "=> Removing internal device " << internal_device->name;
164 }
165
166 device_it = devices->erase(device_it);
167 }
168
169 if (!matched && internal_display)
170 VLOG(2) << "=> Removing internal display " << internal_display->name();
171 }
172
173 void AssociateSameSizeDevices(DisplayInfoList* displays, DeviceList* devices) {
174 // Associate screens/displays with the same size.
175 VLOG(2) << "Trying to match same-size devices (" << displays->size()
176 << " displays and " << devices->size() << " devices to match)";
177
178 DisplayInfoList::iterator display_it = displays->begin();
179 while (display_it != displays->end()) {
180 ManagedDisplayInfo* display = *display_it;
181 const gfx::Size native_size = display->GetNativeModeSize();
182
183 // Try to find an input device with roughly the same size as the display.
184 DeviceList::iterator device_it = std::find_if(
185 devices->begin(), devices->end(),
186 [&native_size](const ui::TouchscreenDevice* device) {
187 // Allow 1 pixel difference between screen and touchscreen
188 // resolutions. Because in some cases for monitor resolution
189 // 1024x768 touchscreen's resolution would be 1024x768, but for
190 // some 1023x767. It really depends on touchscreen's firmware
191 // configuration.
192 return std::abs(native_size.width() - device->size.width()) <= 1 &&
193 std::abs(native_size.height() - device->size.height()) <= 1;
194 });
195
196 if (device_it != devices->end()) {
197 const ui::TouchscreenDevice* device = *device_it;
198 VLOG(2) << "=> Matched device " << device->name << " to display "
199 << display->name() << " (display_size: " << native_size.ToString()
200 << ", device_size: " << device->size.ToString() << ")";
201 Associate(display, device);
202
203 display_it = displays->erase(display_it);
204 device_it = devices->erase(device_it);
205 continue;
206 }
207
208 // Didn't find an input device. Skip this display.
209 ++display_it;
210 }
211 }
212
213 void AssociateToSingleDisplay(DisplayInfoList* displays, DeviceList* devices) {
214 // If there is only one display left, then we should associate all input
215 // devices with it.
216
217 VLOG(2) << "Trying to match to single display (" << displays->size()
218 << " displays and " << devices->size() << " devices to match)";
219
220 // We only associate to one display.
221 if (displays->size() != 1 || devices->empty())
222 return;
223
224 ManagedDisplayInfo* display = *displays->begin();
225 for (const ui::TouchscreenDevice* device : *devices) {
226 VLOG(2) << "=> Matched device " << device->name << " to display "
227 << display->name();
228 Associate(display, device);
229 }
230
231 displays->clear();
232 devices->clear();
233 }
234
235 } // namespace
236
237 void AssociateTouchscreens(
238 std::vector<ManagedDisplayInfo>* all_displays,
239 const std::vector<ui::TouchscreenDevice>& all_devices) {
240 // |displays| and |devices| contain pointers directly to the values stored
241 // inside of |all_displays| and |all_devices|. When a display or input device
242 // has been associated, it is removed from the |displays| or |devices| list.
243
244 // Construct our initial set of display/devices that we will process.
245 DisplayInfoList displays;
246 for (ManagedDisplayInfo& display : *all_displays) {
247 display.ClearInputDevices();
248
249 if (display.GetNativeModeSize().IsEmpty()) {
250 VLOG(2) << "Will not match display " << display.id()
251 << " since it doesn't have a native mode";
252 continue;
253 }
254 displays.push_back(&display);
255 }
256
257 // Construct initial set of devices.
258 DeviceList devices;
259 for (const ui::TouchscreenDevice& device : all_devices)
260 devices.push_back(&device);
261
262 for (const ManagedDisplayInfo* display : displays) {
263 VLOG(2) << "Received display " << display->name()
264 << " (size: " << display->GetNativeModeSize().ToString()
265 << ", sys_path: " << display->sys_path().LossyDisplayName() << ")";
266 }
267 for (const ui::TouchscreenDevice* device : devices) {
268 VLOG(2) << "Received device " << device->name
269 << " (size: " << device->size.ToString()
270 << ", sys_path: " << device->sys_path.LossyDisplayName() << ")";
271 }
272
273 AssociateInternalDevices(&displays, &devices);
274 AssociateUdlDevices(&displays, &devices);
275 AssociateSameSizeDevices(&displays, &devices);
276 AssociateToSingleDisplay(&displays, &devices);
277
278 for (const ManagedDisplayInfo* display : displays)
279 LOG(WARNING) << "Unmatched display " << display->name();
280 for (const ui::TouchscreenDevice* device : devices)
281 LOG(WARNING) << "Unmatched device " << device->name;
282 }
283
284 } // namespace display
OLDNEW
« no previous file with comments | « ui/display/chromeos/touchscreen_util.h ('k') | ui/display/chromeos/touchscreen_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698