ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / device_sensors / data_fetcher_shared_memory_win.cc
blob77c962ecd9b97b80fb2c3cc30ca1b6f5d47a75f4
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.
5 #include "content/browser/device_sensors/data_fetcher_shared_memory.h"
7 #include <GuidDef.h>
8 #include <InitGuid.h>
9 #include <PortableDeviceTypes.h>
10 #include <Sensors.h>
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/win/iunknown_impl.h"
15 #include "base/win/windows_version.h"
17 namespace {
19 const double kMeanGravity = 9.80665;
21 } // namespace
24 namespace content {
26 class DataFetcherSharedMemory::SensorEventSink
27 : public ISensorEvents, public base::win::IUnknownImpl {
28 public:
29 SensorEventSink() {}
30 virtual ~SensorEventSink() {}
32 // IUnknown interface
33 virtual ULONG STDMETHODCALLTYPE AddRef() override {
34 return IUnknownImpl::AddRef();
37 virtual ULONG STDMETHODCALLTYPE Release() override {
38 return IUnknownImpl::Release();
41 virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
42 if (riid == __uuidof(ISensorEvents)) {
43 *ppv = static_cast<ISensorEvents*>(this);
44 AddRef();
45 return S_OK;
47 return IUnknownImpl::QueryInterface(riid, ppv);
50 // ISensorEvents interface
51 STDMETHODIMP OnEvent(ISensor* sensor,
52 REFGUID event_id,
53 IPortableDeviceValues* event_data) override {
54 return S_OK;
57 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
58 return S_OK;
61 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
62 return S_OK;
65 STDMETHODIMP OnDataUpdated(ISensor* sensor,
66 ISensorDataReport* new_data) override {
67 if (nullptr == new_data || nullptr == sensor)
68 return E_INVALIDARG;
69 return UpdateSharedMemoryBuffer(sensor, new_data) ? S_OK : E_FAIL;
72 protected:
73 virtual bool UpdateSharedMemoryBuffer(
74 ISensor* sensor, ISensorDataReport* new_data) = 0;
76 void GetSensorValue(REFPROPERTYKEY property, ISensorDataReport* new_data,
77 double* value, bool* has_value) {
78 PROPVARIANT variant_value = {};
79 if (SUCCEEDED(new_data->GetSensorValue(property, &variant_value))) {
80 if (variant_value.vt == VT_R8)
81 *value = variant_value.dblVal;
82 else if (variant_value.vt == VT_R4)
83 *value = variant_value.fltVal;
84 *has_value = true;
85 } else {
86 *value = 0;
87 *has_value = false;
91 private:
93 DISALLOW_COPY_AND_ASSIGN(SensorEventSink);
96 class DataFetcherSharedMemory::SensorEventSinkOrientation
97 : public DataFetcherSharedMemory::SensorEventSink {
98 public:
99 explicit SensorEventSinkOrientation(
100 DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {}
101 virtual ~SensorEventSinkOrientation() {}
103 protected:
104 virtual bool UpdateSharedMemoryBuffer(
105 ISensor* sensor, ISensorDataReport* new_data) override {
106 double alpha, beta, gamma;
107 bool has_alpha, has_beta, has_gamma;
109 GetSensorValue(SENSOR_DATA_TYPE_TILT_X_DEGREES, new_data, &alpha,
110 &has_alpha);
111 GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES, new_data, &beta,
112 &has_beta);
113 GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES, new_data, &gamma,
114 &has_gamma);
116 if (buffer_) {
117 buffer_->seqlock.WriteBegin();
118 buffer_->data.alpha = alpha;
119 buffer_->data.hasAlpha = has_alpha;
120 buffer_->data.beta = beta;
121 buffer_->data.hasBeta = has_beta;
122 buffer_->data.gamma = gamma;
123 buffer_->data.hasGamma = has_gamma;
124 buffer_->data.absolute = true;
125 buffer_->data.hasAbsolute = has_alpha || has_beta || has_gamma;
126 buffer_->data.allAvailableSensorsAreActive = true;
127 buffer_->seqlock.WriteEnd();
130 return true;
133 private:
134 DeviceOrientationHardwareBuffer* const buffer_;
136 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation);
139 class DataFetcherSharedMemory::SensorEventSinkMotion
140 : public DataFetcherSharedMemory::SensorEventSink {
141 public:
142 explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer)
143 : buffer_(buffer) {}
144 virtual ~SensorEventSinkMotion() {}
146 protected:
147 virtual bool UpdateSharedMemoryBuffer(
148 ISensor* sensor, ISensorDataReport* new_data) override {
150 SENSOR_TYPE_ID sensor_type = GUID_NULL;
151 if (!SUCCEEDED(sensor->GetType(&sensor_type)))
152 return false;
154 if (IsEqualIID(sensor_type, SENSOR_TYPE_ACCELEROMETER_3D)) {
155 double acceleration_including_gravity_x;
156 double acceleration_including_gravity_y;
157 double acceleration_including_gravity_z;
158 bool has_acceleration_including_gravity_x;
159 bool has_acceleration_including_gravity_y;
160 bool has_acceleration_including_gravity_z;
162 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, new_data,
163 &acceleration_including_gravity_x,
164 &has_acceleration_including_gravity_x);
165 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, new_data,
166 &acceleration_including_gravity_y,
167 &has_acceleration_including_gravity_y);
168 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, new_data,
169 &acceleration_including_gravity_z,
170 &has_acceleration_including_gravity_z);
172 if (buffer_) {
173 buffer_->seqlock.WriteBegin();
174 buffer_->data.accelerationIncludingGravityX =
175 -acceleration_including_gravity_x * kMeanGravity;
176 buffer_->data.hasAccelerationIncludingGravityX =
177 has_acceleration_including_gravity_x;
178 buffer_->data.accelerationIncludingGravityY =
179 -acceleration_including_gravity_y * kMeanGravity;
180 buffer_->data.hasAccelerationIncludingGravityY =
181 has_acceleration_including_gravity_y;
182 buffer_->data.accelerationIncludingGravityZ =
183 -acceleration_including_gravity_z * kMeanGravity;
184 buffer_->data.hasAccelerationIncludingGravityZ =
185 has_acceleration_including_gravity_z;
186 // TODO(timvolodine): consider setting this after all
187 // sensors have fired.
188 buffer_->data.allAvailableSensorsAreActive = true;
189 buffer_->seqlock.WriteEnd();
192 } else if (IsEqualIID(sensor_type, SENSOR_TYPE_GYROMETER_3D)) {
193 double alpha, beta, gamma;
194 bool has_alpha, has_beta, has_gamma;
196 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND,
197 new_data, &alpha, &has_alpha);
198 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND,
199 new_data, &beta, &has_beta);
200 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND,
201 new_data, &gamma, &has_gamma);
203 if (buffer_) {
204 buffer_->seqlock.WriteBegin();
205 buffer_->data.rotationRateAlpha = alpha;
206 buffer_->data.hasRotationRateAlpha = has_alpha;
207 buffer_->data.rotationRateBeta = beta;
208 buffer_->data.hasRotationRateBeta = has_beta;
209 buffer_->data.rotationRateGamma = gamma;
210 buffer_->data.hasRotationRateGamma = has_gamma;
211 buffer_->data.allAvailableSensorsAreActive = true;
212 buffer_->seqlock.WriteEnd();
216 return true;
219 private:
220 DeviceMotionHardwareBuffer* const buffer_;
222 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion);
225 DataFetcherSharedMemory::DataFetcherSharedMemory()
226 : motion_buffer_(nullptr), orientation_buffer_(nullptr) {
229 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
232 DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const {
233 return FETCHER_TYPE_SEPARATE_THREAD;
236 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
237 DCHECK(buffer);
239 switch (consumer_type) {
240 case CONSUMER_TYPE_ORIENTATION:
242 orientation_buffer_ =
243 static_cast<DeviceOrientationHardwareBuffer*>(buffer);
244 scoped_refptr<SensorEventSink> sink(
245 new SensorEventSinkOrientation(orientation_buffer_));
246 bool inclinometer_available = RegisterForSensor(
247 SENSOR_TYPE_INCLINOMETER_3D, sensor_inclinometer_.Receive(), sink);
248 UMA_HISTOGRAM_BOOLEAN("InertialSensor.InclinometerWindowsAvailable",
249 inclinometer_available);
250 if (inclinometer_available)
251 return true;
252 // if no sensors are available set buffer to ready, to fire null-events.
253 SetBufferAvailableState(consumer_type, true);
255 break;
256 case CONSUMER_TYPE_MOTION:
258 motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
259 scoped_refptr<SensorEventSink> sink(
260 new SensorEventSinkMotion(motion_buffer_));
261 bool accelerometer_available = RegisterForSensor(
262 SENSOR_TYPE_ACCELEROMETER_3D, sensor_accelerometer_.Receive(),
263 sink);
264 bool gyrometer_available = RegisterForSensor(
265 SENSOR_TYPE_GYROMETER_3D, sensor_gyrometer_.Receive(), sink);
266 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerWindowsAvailable",
267 accelerometer_available);
268 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyrometerWindowsAvailable",
269 gyrometer_available);
270 if (accelerometer_available || gyrometer_available) {
271 motion_buffer_->seqlock.WriteBegin();
272 motion_buffer_->data.interval = GetInterval().InMilliseconds();
273 motion_buffer_->seqlock.WriteEnd();
274 return true;
276 // if no sensors are available set buffer to ready, to fire null-events.
277 SetBufferAvailableState(consumer_type, true);
279 break;
280 default:
281 NOTREACHED();
283 return false;
286 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
287 DisableSensors(consumer_type);
288 SetBufferAvailableState(consumer_type, false);
289 switch (consumer_type) {
290 case CONSUMER_TYPE_ORIENTATION:
291 orientation_buffer_ = nullptr;
292 return true;
293 case CONSUMER_TYPE_MOTION:
294 motion_buffer_ = nullptr;
295 return true;
296 default:
297 NOTREACHED();
299 return false;
302 bool DataFetcherSharedMemory::RegisterForSensor(
303 REFSENSOR_TYPE_ID sensor_type,
304 ISensor** sensor,
305 scoped_refptr<SensorEventSink> event_sink) {
306 if (base::win::GetVersion() < base::win::VERSION_WIN7)
307 return false;
309 base::win::ScopedComPtr<ISensorManager> sensor_manager;
310 HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager);
311 if (FAILED(hr) || !sensor_manager.get())
312 return false;
314 base::win::ScopedComPtr<ISensorCollection> sensor_collection;
315 hr = sensor_manager->GetSensorsByType(
316 sensor_type, sensor_collection.Receive());
318 if (FAILED(hr) || !sensor_collection.get())
319 return false;
321 ULONG count = 0;
322 hr = sensor_collection->GetCount(&count);
323 if (FAILED(hr) || !count)
324 return false;
326 hr = sensor_collection->GetAt(0, sensor);
327 if (FAILED(hr) || !(*sensor))
328 return false;
330 base::win::ScopedComPtr<IPortableDeviceValues> device_values;
331 if (SUCCEEDED(device_values.CreateInstance(CLSID_PortableDeviceValues))) {
332 if (SUCCEEDED(device_values->SetUnsignedIntegerValue(
333 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL,
334 GetInterval().InMilliseconds()))) {
335 base::win::ScopedComPtr<IPortableDeviceValues> return_values;
336 (*sensor)->SetProperties(device_values.get(), return_values.Receive());
340 base::win::ScopedComPtr<ISensorEvents> sensor_events;
341 hr = event_sink->QueryInterface(
342 __uuidof(ISensorEvents), sensor_events.ReceiveVoid());
343 if (FAILED(hr) || !sensor_events.get())
344 return false;
346 hr = (*sensor)->SetEventSink(sensor_events.get());
347 if (FAILED(hr))
348 return false;
350 return true;
353 void DataFetcherSharedMemory::DisableSensors(ConsumerType consumer_type) {
354 switch(consumer_type) {
355 case CONSUMER_TYPE_ORIENTATION:
356 if (sensor_inclinometer_.get()) {
357 sensor_inclinometer_->SetEventSink(nullptr);
358 sensor_inclinometer_.Release();
360 break;
361 case CONSUMER_TYPE_MOTION:
362 if (sensor_accelerometer_.get()) {
363 sensor_accelerometer_->SetEventSink(nullptr);
364 sensor_accelerometer_.Release();
366 if (sensor_gyrometer_.get()) {
367 sensor_gyrometer_->SetEventSink(nullptr);
368 sensor_gyrometer_.Release();
370 break;
371 default:
372 NOTREACHED();
376 void DataFetcherSharedMemory::SetBufferAvailableState(
377 ConsumerType consumer_type, bool enabled) {
378 switch(consumer_type) {
379 case CONSUMER_TYPE_ORIENTATION:
380 if (orientation_buffer_) {
381 orientation_buffer_->seqlock.WriteBegin();
382 orientation_buffer_->data.allAvailableSensorsAreActive = enabled;
383 orientation_buffer_->seqlock.WriteEnd();
385 break;
386 case CONSUMER_TYPE_MOTION:
387 if (motion_buffer_) {
388 motion_buffer_->seqlock.WriteBegin();
389 motion_buffer_->data.allAvailableSensorsAreActive = enabled;
390 motion_buffer_->seqlock.WriteEnd();
392 break;
393 default:
394 NOTREACHED();
398 } // namespace content